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 ? TRUE
723 : FALSE;
724
725 if (hasPrefix)
726 {
727 if (cchPath < 6)
728 return S_FALSE;
729
730 if (IsCharAlpha(pszPath[4]) && (pszPath[5] == ':')) /* like C: */
731 {
732 memmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
733 /* since the passed pszPath must not necessarily be null terminated
734 * and we always have enough space after the strip we can always
735 * ensure the null termination of the stripped result
736 */
737 pszPath[cchPath - 4] = 0;
738 return S_OK;
739 }
740 }
741
742 return S_FALSE;
743}
744
745HRESULT PathCchStripPrefixW(PWSTR pszPath, size_t cchPath)
746{
747 BOOL hasPrefix = 0;
748
749 if (!pszPath)
750 return E_INVALIDARG;
751
752 if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
753 return E_INVALIDARG;
754
755 hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
756 (pszPath[3] == '\\'))
757 ? TRUE
758 : FALSE;
759
760 if (hasPrefix)
761 {
762 if (cchPath < 6)
763 return S_FALSE;
764
765 const size_t rc = (_wcslen(&pszPath[4]) + 1);
766 if (cchPath < rc)
767 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
768
769 if (IsCharAlphaW(pszPath[4]) && (pszPath[5] == L':')) /* like C: */
770 {
771 wmemmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
772 /* since the passed pszPath must not necessarily be null terminated
773 * and we always have enough space after the strip we can always
774 * ensure the null termination of the stripped result
775 */
776 pszPath[cchPath - 4] = 0;
777 return S_OK;
778 }
779 }
780
781 return S_FALSE;
782}
783
788HRESULT PathCchRemoveFileSpecA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
789{
790 WLog_ERR(TAG, "not implemented");
791 return E_NOTIMPL;
792}
793
794HRESULT PathCchRemoveFileSpecW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
795{
796 WLog_ERR(TAG, "not implemented");
797 return E_NOTIMPL;
798}
799
800/*
801 * Path Portability Functions
802 */
803
808HRESULT PathCchConvertStyleA(PSTR pszPath, size_t cchPath, unsigned long dwFlags)
809{
810 if (dwFlags == PATH_STYLE_WINDOWS)
811 {
812 for (size_t index = 0; index < cchPath; index++)
813 {
814 if (pszPath[index] == PATH_SLASH_CHR)
815 pszPath[index] = PATH_BACKSLASH_CHR;
816 }
817 }
818 else if (dwFlags == PATH_STYLE_UNIX)
819 {
820 for (size_t index = 0; index < cchPath; index++)
821 {
822 if (pszPath[index] == PATH_BACKSLASH_CHR)
823 pszPath[index] = PATH_SLASH_CHR;
824 }
825 }
826 else if (dwFlags == PATH_STYLE_NATIVE)
827 {
828 if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
829 {
830 /* Unix-style to Windows-style */
831
832 for (size_t index = 0; index < cchPath; index++)
833 {
834 if (pszPath[index] == PATH_SLASH_CHR)
835 pszPath[index] = PATH_BACKSLASH_CHR;
836 }
837 }
838 else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
839 {
840 /* Windows-style to Unix-style */
841
842 for (size_t index = 0; index < cchPath; index++)
843 {
844 if (pszPath[index] == PATH_BACKSLASH_CHR)
845 pszPath[index] = PATH_SLASH_CHR;
846 }
847 }
848 else
849 {
850 /* Unexpected error */
851 return E_FAIL;
852 }
853 }
854 else
855 {
856 /* Gangnam style? */
857 return E_FAIL;
858 }
859
860 return S_OK;
861}
862
863HRESULT PathCchConvertStyleW(PWSTR pszPath, size_t cchPath, unsigned long dwFlags)
864{
865 if (dwFlags == PATH_STYLE_WINDOWS)
866 {
867 for (size_t index = 0; index < cchPath; index++)
868 {
869 if (pszPath[index] == PATH_SLASH_CHR_W)
870 pszPath[index] = PATH_BACKSLASH_CHR_W;
871 }
872 }
873 else if (dwFlags == PATH_STYLE_UNIX)
874 {
875 for (size_t index = 0; index < cchPath; index++)
876 {
877 if (pszPath[index] == PATH_BACKSLASH_CHR_W)
878 pszPath[index] = PATH_SLASH_CHR_W;
879 }
880 }
881 else if (dwFlags == PATH_STYLE_NATIVE)
882 {
883 if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR_W)
884 {
885 /* Unix-style to Windows-style */
886
887 for (size_t index = 0; index < cchPath; index++)
888 {
889 if (pszPath[index] == PATH_SLASH_CHR_W)
890 pszPath[index] = PATH_BACKSLASH_CHR_W;
891 }
892 }
893 else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR_W)
894 {
895 /* Windows-style to Unix-style */
896
897 for (size_t index = 0; index < cchPath; index++)
898 {
899 if (pszPath[index] == PATH_BACKSLASH_CHR_W)
900 pszPath[index] = PATH_SLASH_CHR_W;
901 }
902 }
903 else
904 {
905 /* Unexpected error */
906 return E_FAIL;
907 }
908 }
909 else
910 {
911 /* Gangnam style? */
912 return E_FAIL;
913 }
914
915 return S_OK;
916}
917
922char PathGetSeparatorA(unsigned long dwFlags)
923{
924 char separator = PATH_SEPARATOR_CHR;
925
926 if (!dwFlags)
927 dwFlags = PATH_STYLE_NATIVE;
928
929 if (dwFlags == PATH_STYLE_WINDOWS)
930 separator = PATH_SEPARATOR_CHR;
931 else if (dwFlags == PATH_STYLE_UNIX)
932 separator = PATH_SEPARATOR_CHR;
933 else if (dwFlags == PATH_STYLE_NATIVE)
934 separator = PATH_SEPARATOR_CHR;
935
936 return separator;
937}
938
939WCHAR PathGetSeparatorW(unsigned long dwFlags)
940{
941 union
942 {
943 WCHAR w;
944 char c[2];
945 } cnv;
946
947 cnv.c[0] = PATH_SEPARATOR_CHR;
948 cnv.c[1] = '\0';
949
950 if (!dwFlags)
951 dwFlags = PATH_STYLE_NATIVE;
952
953 if (dwFlags == PATH_STYLE_WINDOWS)
954 cnv.c[0] = PATH_SEPARATOR_CHR;
955 else if (dwFlags == PATH_STYLE_UNIX)
956 cnv.c[0] = PATH_SEPARATOR_CHR;
957 else if (dwFlags == PATH_STYLE_NATIVE)
958 cnv.c[0] = PATH_SEPARATOR_CHR;
959
960 return cnv.w;
961}
962
966static const CHAR SharedLibraryExtensionDllA[] = "dll";
967static const CHAR SharedLibraryExtensionSoA[] = "so";
968static const CHAR SharedLibraryExtensionDylibA[] = "dylib";
969
970static const CHAR SharedLibraryExtensionDotDllA[] = ".dll";
971static const CHAR SharedLibraryExtensionDotSoA[] = ".so";
972static const CHAR SharedLibraryExtensionDotDylibA[] = ".dylib";
973PCSTR PathGetSharedLibraryExtensionA(unsigned long dwFlags)
974{
975 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
976 {
977 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
978 {
979 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
980 return SharedLibraryExtensionDotDllA;
981
982 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
983 return SharedLibraryExtensionDotSoA;
984
985 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
986 return SharedLibraryExtensionDotDylibA;
987 }
988 else
989 {
990 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
991 return SharedLibraryExtensionDllA;
992
993 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
994 return SharedLibraryExtensionSoA;
995
996 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
997 return SharedLibraryExtensionDylibA;
998 }
999 }
1000
1001 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1002 {
1003#ifdef _WIN32
1004 return SharedLibraryExtensionDotDllA;
1005#elif defined(__APPLE__)
1006 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1007 return SharedLibraryExtensionDotSoA;
1008 else
1009 return SharedLibraryExtensionDotDylibA;
1010#else
1011 return SharedLibraryExtensionDotSoA;
1012#endif
1013 }
1014 else
1015 {
1016#ifdef _WIN32
1017 return SharedLibraryExtensionDllA;
1018#elif defined(__APPLE__)
1019 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1020 return SharedLibraryExtensionSoA;
1021 else
1022 return SharedLibraryExtensionDylibA;
1023#else
1024 return SharedLibraryExtensionSoA;
1025#endif
1026 }
1027
1028 return NULL;
1029}
1030
1031PCWSTR PathGetSharedLibraryExtensionW(unsigned long dwFlags)
1032{
1033 static WCHAR buffer[6][16] = { 0 };
1034 const WCHAR* SharedLibraryExtensionDotDllW = InitializeConstWCharFromUtf8(
1035 SharedLibraryExtensionDotDllA, buffer[0], ARRAYSIZE(buffer[0]));
1036 const WCHAR* SharedLibraryExtensionDotSoW =
1037 InitializeConstWCharFromUtf8(SharedLibraryExtensionDotSoA, buffer[1], ARRAYSIZE(buffer[1]));
1038 const WCHAR* SharedLibraryExtensionDotDylibW = InitializeConstWCharFromUtf8(
1039 SharedLibraryExtensionDotDylibA, buffer[2], ARRAYSIZE(buffer[2]));
1040 const WCHAR* SharedLibraryExtensionDllW =
1041 InitializeConstWCharFromUtf8(SharedLibraryExtensionDllA, buffer[3], ARRAYSIZE(buffer[3]));
1042 const WCHAR* SharedLibraryExtensionSoW =
1043 InitializeConstWCharFromUtf8(SharedLibraryExtensionSoA, buffer[4], ARRAYSIZE(buffer[4]));
1044 const WCHAR* SharedLibraryExtensionDylibW =
1045 InitializeConstWCharFromUtf8(SharedLibraryExtensionDylibA, buffer[5], ARRAYSIZE(buffer[5]));
1046
1047 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
1048 {
1049 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1050 {
1051 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1052 return SharedLibraryExtensionDotDllW;
1053
1054 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1055 return SharedLibraryExtensionDotSoW;
1056
1057 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1058 return SharedLibraryExtensionDotDylibW;
1059 }
1060 else
1061 {
1062 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
1063 return SharedLibraryExtensionDllW;
1064
1065 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
1066 return SharedLibraryExtensionSoW;
1067
1068 if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
1069 return SharedLibraryExtensionDylibW;
1070 }
1071 }
1072
1073 if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
1074 {
1075#ifdef _WIN32
1076 return SharedLibraryExtensionDotDllW;
1077#elif defined(__APPLE__)
1078 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1079 return SharedLibraryExtensionDotSoW;
1080 else
1081 return SharedLibraryExtensionDotDylibW;
1082#else
1083 return SharedLibraryExtensionDotSoW;
1084#endif
1085 }
1086 else
1087 {
1088#ifdef _WIN32
1089 return SharedLibraryExtensionDllW;
1090#elif defined(__APPLE__)
1091 if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
1092 return SharedLibraryExtensionSoW;
1093 else
1094 return SharedLibraryExtensionDylibW;
1095#else
1096 return SharedLibraryExtensionSoW;
1097#endif
1098 }
1099
1100 return NULL;
1101}
1102
1103const char* GetKnownPathIdString(int id)
1104{
1105 switch (id)
1106 {
1107 case KNOWN_PATH_HOME:
1108 return "KNOWN_PATH_HOME";
1109 case KNOWN_PATH_TEMP:
1110 return "KNOWN_PATH_TEMP";
1111 case KNOWN_PATH_XDG_DATA_HOME:
1112 return "KNOWN_PATH_XDG_DATA_HOME";
1113 case KNOWN_PATH_XDG_CONFIG_HOME:
1114 return "KNOWN_PATH_XDG_CONFIG_HOME";
1115 case KNOWN_PATH_XDG_CACHE_HOME:
1116 return "KNOWN_PATH_XDG_CACHE_HOME";
1117 case KNOWN_PATH_XDG_RUNTIME_DIR:
1118 return "KNOWN_PATH_XDG_RUNTIME_DIR";
1119 case KNOWN_PATH_SYSTEM_CONFIG_HOME:
1120 return "KNOWN_PATH_SYSTEM_CONFIG_HOME";
1121 default:
1122 return "KNOWN_PATH_UNKNOWN_ID";
1123 }
1124}
1125
1126static char* concat(const char* path, size_t pathlen, const char* name, size_t namelen)
1127{
1128 const size_t strsize = pathlen + namelen + 2;
1129 char* str = calloc(strsize, sizeof(char));
1130 if (!str)
1131 return NULL;
1132
1133 winpr_str_append(path, str, strsize, "");
1134 winpr_str_append(name, str, strsize, "");
1135 return str;
1136}
1137
1138BOOL winpr_RemoveDirectory_RecursiveA(LPCSTR lpPathName)
1139{
1140 BOOL ret = FALSE;
1141
1142 if (!lpPathName)
1143 return FALSE;
1144
1145 const size_t pathnamelen = strlen(lpPathName);
1146 const size_t path_slash_len = pathnamelen + 3;
1147 char* path_slash = calloc(pathnamelen + 4, sizeof(char));
1148 if (!path_slash)
1149 return FALSE;
1150 strncat(path_slash, lpPathName, pathnamelen);
1151
1152 const char star[] = "*";
1153 const HRESULT hr = NativePathCchAppendA(path_slash, path_slash_len, star);
1154 HANDLE dir = INVALID_HANDLE_VALUE;
1155 if (FAILED(hr))
1156 goto fail;
1157
1158 {
1159 WIN32_FIND_DATAA findFileData = { 0 };
1160 dir = FindFirstFileA(path_slash, &findFileData);
1161
1162 if (dir == INVALID_HANDLE_VALUE)
1163 goto fail;
1164
1165 ret = TRUE;
1166 path_slash[path_slash_len - 1] = '\0'; /* remove trailing '*' */
1167 do
1168 {
1169 const size_t len = strnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
1170
1171 if ((len == 1 && findFileData.cFileName[0] == '.') ||
1172 (len == 2 && findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.'))
1173 {
1174 continue;
1175 }
1176
1177 char* fullpath = concat(path_slash, path_slash_len, findFileData.cFileName, len);
1178 if (!fullpath)
1179 goto fail;
1180
1181 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1182 ret = winpr_RemoveDirectory_RecursiveA(fullpath);
1183 else
1184 {
1185 WINPR_PRAGMA_DIAG_PUSH
1186 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
1187 ret = DeleteFileA(fullpath);
1188 WINPR_PRAGMA_DIAG_POP
1189 }
1190
1191 free(fullpath);
1192
1193 if (!ret)
1194 break;
1195 } while (ret && FindNextFileA(dir, &findFileData) != 0);
1196 }
1197
1198 if (ret)
1199 {
1200 WINPR_PRAGMA_DIAG_PUSH
1201 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
1202 if (!RemoveDirectoryA(lpPathName))
1203 ret = FALSE;
1204 WINPR_PRAGMA_DIAG_POP
1205 }
1206
1207fail:
1208 FindClose(dir);
1209 free(path_slash);
1210 return ret;
1211}
1212
1213BOOL winpr_RemoveDirectory_RecursiveW(LPCWSTR lpPathName)
1214{
1215 char* name = ConvertWCharToUtf8Alloc(lpPathName, NULL);
1216 if (!name)
1217 return FALSE;
1218 const BOOL rc = winpr_RemoveDirectory_RecursiveA(name);
1219 free(name);
1220 return rc;
1221}
1222
1223char* winpr_GetConfigFilePathVA(BOOL system, WINPR_FORMAT_ARG const char* filename, va_list ap)
1224{
1225 eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME;
1226 const char* vendor = winpr_getApplicationDetailsVendor();
1227 const char* product = winpr_getApplicationDetailsProduct();
1228 const SSIZE_T version = winpr_getApplicationDetailsVersion();
1229
1230 if (!vendor || !product)
1231 return NULL;
1232
1233 char* config = GetKnownSubPathV(id, "%s", vendor);
1234 if (!config)
1235 return NULL;
1236
1237 char* base = NULL;
1238 if (version < 0)
1239 base = GetCombinedPathV(config, "%s", product);
1240 else
1241 base = GetCombinedPathV(config, "%s%" PRIdz, product, version);
1242 free(config);
1243
1244 if (!base)
1245 return NULL;
1246 char* path = GetCombinedPathVA(base, filename, ap);
1247 free(base);
1248
1249 return path;
1250}
1251
1252char* winpr_GetConfigFilePath(BOOL system, const char* filename)
1253{
1254 if (!filename)
1255 return winpr_GetConfigFilePathV(system, "%s", "");
1256 return winpr_GetConfigFilePathV(system, "%s", filename);
1257}
1258
1259char* winpr_GetConfigFilePathV(BOOL system, const char* filename, ...)
1260{
1261 va_list ap;
1262 va_start(ap, filename);
1263 char* str = winpr_GetConfigFilePathVA(system, filename, ap);
1264 va_end(ap);
1265 return str;
1266}