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