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