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_RESOURCE_VERSIONING)
33#define STR(x) #x
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/*
371 * PathCchCanonicalize
372 */
373
374HRESULT PathCchCanonicalizeA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
375 WINPR_ATTR_UNUSED PCSTR pszPathIn)
376{
377 WLog_ERR(TAG, "not implemented");
378 return E_NOTIMPL;
379}
380
381HRESULT PathCchCanonicalizeW(WINPR_ATTR_UNUSED PWSTR pszPathOut,
382 WINPR_ATTR_UNUSED size_t cchPathOut,
383 WINPR_ATTR_UNUSED PCWSTR pszPathIn)
384{
385 WLog_ERR(TAG, "not implemented");
386 return E_NOTIMPL;
387}
388
389/*
390 * PathCchCanonicalizeEx
391 */
392
393HRESULT PathCchCanonicalizeExA(WINPR_ATTR_UNUSED PSTR pszPathOut,
394 WINPR_ATTR_UNUSED size_t cchPathOut,
395 WINPR_ATTR_UNUSED PCSTR pszPathIn,
396 WINPR_ATTR_UNUSED unsigned long dwFlags)
397{
398 WLog_ERR(TAG, "not implemented");
399 return E_NOTIMPL;
400}
401
402HRESULT PathCchCanonicalizeExW(WINPR_ATTR_UNUSED PWSTR pszPathOut,
403 WINPR_ATTR_UNUSED size_t cchPathOut,
404 WINPR_ATTR_UNUSED PCWSTR pszPathIn,
405 WINPR_ATTR_UNUSED unsigned long dwFlags)
406{
407 WLog_ERR(TAG, "not implemented");
408 return E_NOTIMPL;
409}
410
411/*
412 * PathAllocCanonicalize
413 */
414
415HRESULT PathAllocCanonicalizeA(WINPR_ATTR_UNUSED PCSTR pszPathIn,
416 WINPR_ATTR_UNUSED unsigned long dwFlags,
417 WINPR_ATTR_UNUSED PSTR* ppszPathOut)
418{
419 WLog_ERR(TAG, "not implemented");
420 return E_NOTIMPL;
421}
422
423HRESULT PathAllocCanonicalizeW(WINPR_ATTR_UNUSED PCWSTR pszPathIn,
424 WINPR_ATTR_UNUSED unsigned long dwFlags,
425 WINPR_ATTR_UNUSED PWSTR* ppszPathOut)
426{
427 WLog_ERR(TAG, "not implemented");
428 return E_NOTIMPL;
429}
430
431/*
432 * PathCchCombine
433 */
434
435HRESULT PathCchCombineA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
436 WINPR_ATTR_UNUSED PCSTR pszPathIn, WINPR_ATTR_UNUSED PCSTR pszMore)
437{
438 WLog_ERR(TAG, "not implemented");
439 return E_NOTIMPL;
440}
441
442HRESULT PathCchCombineW(WINPR_ATTR_UNUSED PWSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
443 WINPR_ATTR_UNUSED PCWSTR pszPathIn, WINPR_ATTR_UNUSED PCWSTR pszMore)
444{
445 WLog_ERR(TAG, "not implemented");
446 return E_NOTIMPL;
447}
448
449/*
450 * PathCchCombineEx
451 */
452
453HRESULT PathCchCombineExA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
454 WINPR_ATTR_UNUSED PCSTR pszPathIn, WINPR_ATTR_UNUSED PCSTR pszMore,
455 WINPR_ATTR_UNUSED unsigned long dwFlags)
456{
457 WLog_ERR(TAG, "not implemented");
458 return E_NOTIMPL;
459}
460
461HRESULT PathCchCombineExW(WINPR_ATTR_UNUSED PWSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
462 WINPR_ATTR_UNUSED PCWSTR pszPathIn, WINPR_ATTR_UNUSED PCWSTR pszMore,
463 WINPR_ATTR_UNUSED unsigned long dwFlags)
464{
465 WLog_ERR(TAG, "not implemented");
466 return E_NOTIMPL;
467}
468
469/*
470 * PathAllocCombine
471 */
472
473/* Windows-style Paths */
474
475#define DEFINE_UNICODE FALSE
476#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
477#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
478#define PATH_ALLOC_COMBINE PathAllocCombineA
479#include "include/PathAllocCombine.h"
480#undef DEFINE_UNICODE
481#undef CUR_PATH_SEPARATOR_CHR
482#undef CUR_PATH_SEPARATOR_STR
483#undef PATH_ALLOC_COMBINE
484
485#define DEFINE_UNICODE TRUE
486#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
487#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
488#define PATH_ALLOC_COMBINE PathAllocCombineW
489#include "include/PathAllocCombine.h"
490#undef DEFINE_UNICODE
491#undef CUR_PATH_SEPARATOR_CHR
492#undef CUR_PATH_SEPARATOR_STR
493#undef PATH_ALLOC_COMBINE
494
495/* Unix-style Paths */
496
497#define DEFINE_UNICODE FALSE
498#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
499#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
500#define PATH_ALLOC_COMBINE UnixPathAllocCombineA
501#include "include/PathAllocCombine.h"
502#undef DEFINE_UNICODE
503#undef CUR_PATH_SEPARATOR_CHR
504#undef CUR_PATH_SEPARATOR_STR
505#undef PATH_ALLOC_COMBINE
506
507#define DEFINE_UNICODE TRUE
508#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
509#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
510#define PATH_ALLOC_COMBINE UnixPathAllocCombineW
511#include "include/PathAllocCombine.h"
512#undef DEFINE_UNICODE
513#undef CUR_PATH_SEPARATOR_CHR
514#undef CUR_PATH_SEPARATOR_STR
515#undef PATH_ALLOC_COMBINE
516
517/* Native-style Paths */
518
519#define DEFINE_UNICODE FALSE
520#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
521#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
522#define PATH_ALLOC_COMBINE NativePathAllocCombineA
523#include "include/PathAllocCombine.h"
524#undef DEFINE_UNICODE
525#undef CUR_PATH_SEPARATOR_CHR
526#undef CUR_PATH_SEPARATOR_STR
527#undef PATH_ALLOC_COMBINE
528
529#define DEFINE_UNICODE TRUE
530#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
531#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
532#define PATH_ALLOC_COMBINE NativePathAllocCombineW
533#include "include/PathAllocCombine.h"
534#undef DEFINE_UNICODE
535#undef CUR_PATH_SEPARATOR_CHR
536#undef CUR_PATH_SEPARATOR_STR
537#undef PATH_ALLOC_COMBINE
538
543HRESULT PathCchFindExtensionA(PCSTR pszPath, size_t cchPath, PCSTR* ppszExt)
544{
545 const char* p = (const char*)pszPath;
546
547 if (!pszPath || !cchPath || !ppszExt)
548 return E_INVALIDARG;
549
550 /* find end of string */
551
552 while (*p && --cchPath)
553 {
554 p++;
555 }
556
557 if (*p)
558 {
559 /* pszPath is not null terminated within the cchPath range */
560 return E_INVALIDARG;
561 }
562
563 /* If no extension is found, ppszExt must point to the string's terminating null */
564 *ppszExt = p;
565
566 /* search backwards for '.' */
567
568 while (p > pszPath)
569 {
570 if (*p == '.')
571 {
572 *ppszExt = (PCSTR)p;
573 break;
574 }
575
576 if ((*p == '\\') || (*p == '/') || (*p == ':'))
577 break;
578
579 p--;
580 }
581
582 return S_OK;
583}
584
585HRESULT PathCchFindExtensionW(WINPR_ATTR_UNUSED PCWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
586 WINPR_ATTR_UNUSED PCWSTR* ppszExt)
587{
588 WLog_ERR(TAG, "not implemented");
589 return E_NOTIMPL;
590}
591
596HRESULT PathCchRenameExtensionA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
597 WINPR_ATTR_UNUSED PCSTR pszExt)
598{
599 WLog_ERR(TAG, "not implemented");
600 return E_NOTIMPL;
601}
602
603HRESULT PathCchRenameExtensionW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
604 WINPR_ATTR_UNUSED PCWSTR pszExt)
605{
606 WLog_ERR(TAG, "not implemented");
607 return E_NOTIMPL;
608}
609
614HRESULT PathCchRemoveExtensionA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
615{
616 WLog_ERR(TAG, "not implemented");
617 return E_NOTIMPL;
618}
619
620HRESULT PathCchRemoveExtensionW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
621{
622 WLog_ERR(TAG, "not implemented");
623 return E_NOTIMPL;
624}
625
630BOOL PathCchIsRootA(WINPR_ATTR_UNUSED PCSTR pszPath)
631{
632 WLog_ERR(TAG, "not implemented");
633 return FALSE;
634}
635
636BOOL PathCchIsRootW(WINPR_ATTR_UNUSED PCWSTR pszPath)
637{
638 WLog_ERR(TAG, "not implemented");
639 return FALSE;
640}
641
646BOOL PathIsUNCExA(PCSTR pszPath, PCSTR* ppszServer)
647{
648 if (!pszPath)
649 return FALSE;
650
651 if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
652 {
653 *ppszServer = &pszPath[2];
654 return TRUE;
655 }
656
657 return FALSE;
658}
659
660BOOL PathIsUNCExW(PCWSTR pszPath, PCWSTR* ppszServer)
661{
662 if (!pszPath)
663 return FALSE;
664
665 if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
666 {
667 *ppszServer = &pszPath[2];
668 return TRUE;
669 }
670
671 return FALSE;
672}
673
678HRESULT PathCchSkipRootA(WINPR_ATTR_UNUSED PCSTR pszPath, WINPR_ATTR_UNUSED PCSTR* ppszRootEnd)
679{
680 WLog_ERR(TAG, "not implemented");
681 return E_NOTIMPL;
682}
683
684HRESULT PathCchSkipRootW(WINPR_ATTR_UNUSED PCWSTR pszPath, WINPR_ATTR_UNUSED PCWSTR* ppszRootEnd)
685{
686 WLog_ERR(TAG, "not implemented");
687 return E_NOTIMPL;
688}
689
694HRESULT PathCchStripToRootA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
695{
696 WLog_ERR(TAG, "not implemented");
697 return E_NOTIMPL;
698}
699
700HRESULT PathCchStripToRootW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
701{
702 WLog_ERR(TAG, "not implemented");
703 return E_NOTIMPL;
704}
705
710HRESULT PathCchStripPrefixA(PSTR pszPath, size_t cchPath)
711{
712 BOOL hasPrefix = 0;
713
714 if (!pszPath)
715 return E_INVALIDARG;
716
717 if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
718 return E_INVALIDARG;
719
720 hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
721 (pszPath[3] == '\\'));
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
756 if (hasPrefix)
757 {
758 if (cchPath < 6)
759 return S_FALSE;
760
761 const size_t rc = (_wcslen(&pszPath[4]) + 1);
762 if (cchPath < rc)
763 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
764
765 if (IsCharAlphaW(pszPath[4]) && (pszPath[5] == L':')) /* like C: */
766 {
767 wmemmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
768 /* since the passed pszPath must not necessarily be null terminated
769 * and we always have enough space after the strip we can always
770 * ensure the null termination of the stripped result
771 */
772 pszPath[cchPath - 4] = 0;
773 return S_OK;
774 }
775 }
776
777 return S_FALSE;
778}
779
784HRESULT PathCchRemoveFileSpecA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
785{
786 WLog_ERR(TAG, "not implemented");
787 return E_NOTIMPL;
788}
789
790HRESULT PathCchRemoveFileSpecW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
791{
792 WLog_ERR(TAG, "not implemented");
793 return E_NOTIMPL;
794}
795
796/*
797 * Path Portability Functions
798 */
799
804HRESULT PathCchConvertStyleA(PSTR pszPath, size_t cchPath, unsigned long dwFlags)
805{
806 if (dwFlags == PATH_STYLE_WINDOWS)
807 {
808 for (size_t index = 0; index < cchPath; index++)
809 {
810 if (pszPath[index] == PATH_SLASH_CHR)
811 pszPath[index] = PATH_BACKSLASH_CHR;
812 }
813 }
814 else if (dwFlags == PATH_STYLE_UNIX)
815 {
816 for (size_t index = 0; index < cchPath; index++)
817 {
818 if (pszPath[index] == PATH_BACKSLASH_CHR)
819 pszPath[index] = PATH_SLASH_CHR;
820 }
821 }
822 else if (dwFlags == PATH_STYLE_NATIVE)
823 {
824 if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
825 {
826 /* Unix-style to Windows-style */
827
828 for (size_t index = 0; index < cchPath; index++)
829 {
830 if (pszPath[index] == PATH_SLASH_CHR)
831 pszPath[index] = PATH_BACKSLASH_CHR;
832 }
833 }
834 else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
835 {
836 /* Windows-style to Unix-style */
837
838 for (size_t index = 0; index < cchPath; index++)
839 {
840 if (pszPath[index] == PATH_BACKSLASH_CHR)
841 pszPath[index] = PATH_SLASH_CHR;
842 }
843 }
844 else
845 {
846 /* Unexpected error */
847 return E_FAIL;
848 }
849 }
850 else
851 {
852 /* Gangnam style? */
853 return E_FAIL;
854 }
855
856 return S_OK;
857}
858
859HRESULT PathCchConvertStyleW(PWSTR pszPath, size_t cchPath, unsigned long dwFlags)
860{
861 if (dwFlags == PATH_STYLE_WINDOWS)
862 {
863 for (size_t index = 0; index < cchPath; index++)
864 {
865 if (pszPath[index] == PATH_SLASH_CHR_W)
866 pszPath[index] = PATH_BACKSLASH_CHR_W;
867 }
868 }
869 else if (dwFlags == PATH_STYLE_UNIX)
870 {
871 for (size_t index = 0; index < cchPath; index++)
872 {
873 if (pszPath[index] == PATH_BACKSLASH_CHR_W)
874 pszPath[index] = PATH_SLASH_CHR_W;
875 }
876 }
877 else if (dwFlags == PATH_STYLE_NATIVE)
878 {
879 if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR_W)
880 {
881 /* Unix-style to Windows-style */
882
883 for (size_t index = 0; index < cchPath; index++)
884 {
885 if (pszPath[index] == PATH_SLASH_CHR_W)
886 pszPath[index] = PATH_BACKSLASH_CHR_W;
887 }
888 }
889 else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR_W)
890 {
891 /* Windows-style to Unix-style */
892
893 for (size_t index = 0; index < cchPath; index++)
894 {
895 if (pszPath[index] == PATH_BACKSLASH_CHR_W)
896 pszPath[index] = PATH_SLASH_CHR_W;
897 }
898 }
899 else
900 {
901 /* Unexpected error */
902 return E_FAIL;
903 }
904 }
905 else
906 {
907 /* Gangnam style? */
908 return E_FAIL;
909 }
910
911 return S_OK;
912}
913
918char PathGetSeparatorA(unsigned long dwFlags)
919{
920 char separator = PATH_SEPARATOR_CHR;
921
922 if (!dwFlags)
923 dwFlags = PATH_STYLE_NATIVE;
924
925 if (dwFlags == PATH_STYLE_WINDOWS)
926 separator = PATH_SEPARATOR_CHR;
927 else if (dwFlags == PATH_STYLE_UNIX)
928 separator = PATH_SEPARATOR_CHR;
929 else if (dwFlags == PATH_STYLE_NATIVE)
930 separator = PATH_SEPARATOR_CHR;
931
932 return separator;
933}
934
935WCHAR PathGetSeparatorW(unsigned long dwFlags)
936{
937 union
938 {
939 WCHAR w;
940 char c[2];
941 } cnv;
942
943 cnv.c[0] = PATH_SEPARATOR_CHR;
944 cnv.c[1] = '\0';
945
946 if (!dwFlags)
947 dwFlags = PATH_STYLE_NATIVE;
948
949 if (dwFlags == PATH_STYLE_WINDOWS)
950 cnv.c[0] = PATH_SEPARATOR_CHR;
951 else if (dwFlags == PATH_STYLE_UNIX)
952 cnv.c[0] = PATH_SEPARATOR_CHR;
953 else if (dwFlags == PATH_STYLE_NATIVE)
954 cnv.c[0] = PATH_SEPARATOR_CHR;
955
956 return cnv.w;
957}
958
962static const CHAR SharedLibraryExtensionDllA[] = "dll";
963static const CHAR SharedLibraryExtensionSoA[] = "so";
964static const CHAR SharedLibraryExtensionDylibA[] = "dylib";
965
966static const CHAR SharedLibraryExtensionDotDllA[] = ".dll";
967static const CHAR SharedLibraryExtensionDotSoA[] = ".so";
968static const CHAR SharedLibraryExtensionDotDylibA[] = ".dylib";
969PCSTR PathGetSharedLibraryExtensionA(unsigned long dwFlags)
970{
971 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
972 {
973 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
974 {
975 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
976 return SharedLibraryExtensionDotDllA;
977
978 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
979 return SharedLibraryExtensionDotSoA;
980
981 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
982 return SharedLibraryExtensionDotDylibA;
983 }
984 else
985 {
986 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
987 return SharedLibraryExtensionDllA;
988
989 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
990 return SharedLibraryExtensionSoA;
991
992 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
993 return SharedLibraryExtensionDylibA;
994 }
995 }
996
997 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
998 {
999#ifdef _WIN32
1000 return SharedLibraryExtensionDotDllA;
1001#elif defined(__APPLE__)
1002 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1003 return SharedLibraryExtensionDotSoA;
1004 else
1005 return SharedLibraryExtensionDotDylibA;
1006#else
1007 return SharedLibraryExtensionDotSoA;
1008#endif
1009 }
1010 else
1011 {
1012#ifdef _WIN32
1013 return SharedLibraryExtensionDllA;
1014#elif defined(__APPLE__)
1015 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1016 return SharedLibraryExtensionSoA;
1017 else
1018 return SharedLibraryExtensionDylibA;
1019#else
1020 return SharedLibraryExtensionSoA;
1021#endif
1022 }
1023}
1024
1025PCWSTR PathGetSharedLibraryExtensionW(unsigned long dwFlags)
1026{
1027 static WCHAR buffer[6][16] = WINPR_C_ARRAY_INIT;
1028 const WCHAR* SharedLibraryExtensionDotDllW = InitializeConstWCharFromUtf8(
1029 SharedLibraryExtensionDotDllA, buffer[0], ARRAYSIZE(buffer[0]));
1030 const WCHAR* SharedLibraryExtensionDotSoW =
1031 InitializeConstWCharFromUtf8(SharedLibraryExtensionDotSoA, buffer[1], ARRAYSIZE(buffer[1]));
1032 const WCHAR* SharedLibraryExtensionDotDylibW = InitializeConstWCharFromUtf8(
1033 SharedLibraryExtensionDotDylibA, buffer[2], ARRAYSIZE(buffer[2]));
1034 const WCHAR* SharedLibraryExtensionDllW =
1035 InitializeConstWCharFromUtf8(SharedLibraryExtensionDllA, buffer[3], ARRAYSIZE(buffer[3]));
1036 const WCHAR* SharedLibraryExtensionSoW =
1037 InitializeConstWCharFromUtf8(SharedLibraryExtensionSoA, buffer[4], ARRAYSIZE(buffer[4]));
1038 const WCHAR* SharedLibraryExtensionDylibW =
1039 InitializeConstWCharFromUtf8(SharedLibraryExtensionDylibA, buffer[5], ARRAYSIZE(buffer[5]));
1040
1041 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
1042 {
1043 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1044 {
1045 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1046 return SharedLibraryExtensionDotDllW;
1047
1048 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1049 return SharedLibraryExtensionDotSoW;
1050
1051 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1052 return SharedLibraryExtensionDotDylibW;
1053 }
1054 else
1055 {
1056 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1057 return SharedLibraryExtensionDllW;
1058
1059 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1060 return SharedLibraryExtensionSoW;
1061
1062 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1063 return SharedLibraryExtensionDylibW;
1064 }
1065 }
1066
1067 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1068 {
1069#ifdef _WIN32
1070 return SharedLibraryExtensionDotDllW;
1071#elif defined(__APPLE__)
1072 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1073 return SharedLibraryExtensionDotSoW;
1074 else
1075 return SharedLibraryExtensionDotDylibW;
1076#else
1077 return SharedLibraryExtensionDotSoW;
1078#endif
1079 }
1080 else
1081 {
1082#ifdef _WIN32
1083 return SharedLibraryExtensionDllW;
1084#elif defined(__APPLE__)
1085 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1086 return SharedLibraryExtensionSoW;
1087 else
1088 return SharedLibraryExtensionDylibW;
1089#else
1090 return SharedLibraryExtensionSoW;
1091#endif
1092 }
1093}
1094
1095const char* GetKnownPathIdString(int id)
1096{
1097 switch (id)
1098 {
1099 case KNOWN_PATH_HOME:
1100 return "KNOWN_PATH_HOME";
1101 case KNOWN_PATH_TEMP:
1102 return "KNOWN_PATH_TEMP";
1103 case KNOWN_PATH_XDG_DATA_HOME:
1104 return "KNOWN_PATH_XDG_DATA_HOME";
1105 case KNOWN_PATH_XDG_CONFIG_HOME:
1106 return "KNOWN_PATH_XDG_CONFIG_HOME";
1107 case KNOWN_PATH_XDG_CACHE_HOME:
1108 return "KNOWN_PATH_XDG_CACHE_HOME";
1109 case KNOWN_PATH_XDG_RUNTIME_DIR:
1110 return "KNOWN_PATH_XDG_RUNTIME_DIR";
1111 case KNOWN_PATH_SYSTEM_CONFIG_HOME:
1112 return "KNOWN_PATH_SYSTEM_CONFIG_HOME";
1113 default:
1114 return "KNOWN_PATH_UNKNOWN_ID";
1115 }
1116}
1117
1118static char* concat(const char* path, size_t pathlen, const char* name, size_t namelen)
1119{
1120 const size_t strsize = pathlen + namelen + 2;
1121 char* str = calloc(strsize, sizeof(char));
1122 if (!str)
1123 return nullptr;
1124
1125 winpr_str_append(path, str, strsize, "");
1126 winpr_str_append(name, str, strsize, "");
1127 return str;
1128}
1129
1130BOOL winpr_RemoveDirectory_RecursiveA(LPCSTR lpPathName)
1131{
1132 BOOL ret = FALSE;
1133
1134 if (!lpPathName)
1135 return FALSE;
1136
1137 const size_t pathnamelen = strlen(lpPathName);
1138 const size_t path_slash_len = pathnamelen + 3;
1139 char* path_slash = calloc(pathnamelen + 4, sizeof(char));
1140 if (!path_slash)
1141 return FALSE;
1142 strncat(path_slash, lpPathName, pathnamelen);
1143
1144 const char star[] = "*";
1145 const HRESULT hr = NativePathCchAppendA(path_slash, path_slash_len, star);
1146 HANDLE dir = INVALID_HANDLE_VALUE;
1147 if (FAILED(hr))
1148 goto fail;
1149
1150 {
1151 WIN32_FIND_DATAA findFileData = WINPR_C_ARRAY_INIT;
1152 dir = FindFirstFileA(path_slash, &findFileData);
1153
1154 if (dir == INVALID_HANDLE_VALUE)
1155 goto fail;
1156
1157 ret = TRUE;
1158 path_slash[path_slash_len - 1] = '\0'; /* remove trailing '*' */
1159 do
1160 {
1161 const size_t len = strnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
1162
1163 if ((len == 1 && findFileData.cFileName[0] == '.') ||
1164 (len == 2 && findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.'))
1165 {
1166 continue;
1167 }
1168
1169 char* fullpath = concat(path_slash, path_slash_len, findFileData.cFileName, len);
1170 if (!fullpath)
1171 goto fail;
1172
1173 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1174 ret = winpr_RemoveDirectory_RecursiveA(fullpath);
1175 else
1176 {
1177 WINPR_PRAGMA_DIAG_PUSH
1178 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
1179 ret = DeleteFileA(fullpath);
1180 WINPR_PRAGMA_DIAG_POP
1181 }
1182
1183 free(fullpath);
1184
1185 if (!ret)
1186 break;
1187 } while (ret && FindNextFileA(dir, &findFileData) != 0);
1188 }
1189
1190 if (ret)
1191 {
1192 WINPR_PRAGMA_DIAG_PUSH
1193 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
1194 if (!RemoveDirectoryA(lpPathName))
1195 ret = FALSE;
1196 WINPR_PRAGMA_DIAG_POP
1197 }
1198
1199fail:
1200 FindClose(dir);
1201 free(path_slash);
1202 return ret;
1203}
1204
1205BOOL winpr_RemoveDirectory_RecursiveW(LPCWSTR lpPathName)
1206{
1207 char* name = ConvertWCharToUtf8Alloc(lpPathName, nullptr);
1208 if (!name)
1209 return FALSE;
1210 const BOOL rc = winpr_RemoveDirectory_RecursiveA(name);
1211 free(name);
1212 return rc;
1213}
1214
1215char* winpr_GetConfigFilePathVA(BOOL system, WINPR_FORMAT_ARG const char* filename, va_list ap)
1216{
1217 eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME;
1218 const char* vendor = winpr_getApplicationDetailsVendor();
1219 const char* product = winpr_getApplicationDetailsProduct();
1220 const SSIZE_T version = winpr_getApplicationDetailsVersion();
1221
1222 if (!vendor || !product)
1223 return nullptr;
1224
1225 char* config = GetKnownSubPathV(id, "%s", vendor);
1226 if (!config)
1227 return nullptr;
1228
1229 char* base = nullptr;
1230 if (version < 0)
1231 base = GetCombinedPathV(config, "%s", product);
1232 else
1233 base = GetCombinedPathV(config, "%s%" PRIdz, product, version);
1234 free(config);
1235
1236 if (!base)
1237 return nullptr;
1238 char* path = GetCombinedPathVA(base, filename, ap);
1239 free(base);
1240
1241 return path;
1242}
1243
1244char* winpr_GetConfigFilePath(BOOL system, const char* filename)
1245{
1246 if (!filename)
1247 return winpr_GetConfigFilePathV(system, "%s", "");
1248 return winpr_GetConfigFilePathV(system, "%s", filename);
1249}
1250
1251char* winpr_GetConfigFilePathV(BOOL system, const char* filename, ...)
1252{
1253 va_list ap = WINPR_C_ARRAY_INIT;
1254 va_start(ap, filename);
1255 char* str = winpr_GetConfigFilePathVA(system, filename, ap);
1256 va_end(ap);
1257 return str;
1258}