FreeRDP
Loading...
Searching...
No Matches
path/shell.c
1
21#include <winpr/config.h>
22#include <winpr/build-config.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/stat.h>
28
29#include <winpr/crt.h>
30#include <winpr/platform.h>
31#include <winpr/file.h>
32#include <winpr/tchar.h>
33#include <winpr/environment.h>
34
35#include <winpr/path.h>
36#include <winpr/wlog.h>
37
38#include "../log.h"
39#define TAG WINPR_TAG("path.shell")
40
41#if defined(__IOS__)
42#include "shell_ios.h"
43#endif
44
45#if defined(WIN32)
46#include <windows.h>
47#include <shlobj.h>
48#else
49#include <errno.h>
50#include <dirent.h>
51#endif
52
53static char* GetPath_XDG_CONFIG_HOME(void);
54static char* GetPath_XDG_RUNTIME_DIR(void);
55
66char* GetEnvAlloc(LPCSTR lpName)
67{
68 DWORD nSize = 0;
69 DWORD nStatus = 0;
70 char* env = NULL;
71
72 nSize = GetEnvironmentVariableX(lpName, NULL, 0);
73
74 if (nSize > 0)
75 {
76 env = malloc(nSize);
77
78 if (!env)
79 return NULL;
80
81 nStatus = GetEnvironmentVariableX(lpName, env, nSize);
82
83 if (nStatus != (nSize - 1))
84 {
85 free(env);
86 return NULL;
87 }
88 }
89
90 return env;
91}
92
93static char* GetPath_HOME(void)
94{
95 char* path = NULL;
96#ifdef _WIN32
97 path = GetEnvAlloc("UserProfile");
98#elif defined(__IOS__)
99 path = ios_get_home();
100#else
101 path = GetEnvAlloc("HOME");
102#endif
103 return path;
104}
105
106static char* GetPath_TEMP(void)
107{
108 char* path = NULL;
109#ifdef _WIN32
110 path = GetEnvAlloc("TEMP");
111#elif defined(__IOS__)
112 path = ios_get_temp();
113#else
114 path = GetEnvAlloc("TMPDIR");
115
116 if (!path)
117 path = _strdup("/tmp");
118
119#endif
120 return path;
121}
122
123static char* GetPath_XDG_DATA_HOME(void)
124{
125 char* path = NULL;
126#if defined(WIN32) || defined(__IOS__)
127 path = GetPath_XDG_CONFIG_HOME();
128#else
129 size_t size = 0;
130 char* home = NULL;
139 path = GetEnvAlloc("XDG_DATA_HOME");
140
141 if (path)
142 return path;
143
144 home = GetPath_HOME();
145
146 if (!home)
147 return NULL;
148
149 size = strlen(home) + strlen("/.local/share") + 1;
150 path = (char*)malloc(size);
151
152 if (!path)
153 {
154 free(home);
155 return NULL;
156 }
157
158 (void)sprintf_s(path, size, "%s%s", home, "/.local/share");
159 free(home);
160#endif
161 return path;
162}
163
164static char* GetPath_XDG_CONFIG_HOME(void)
165{
166 char* path = NULL;
167#if defined(WIN32) && !defined(_UWP)
168 path = calloc(MAX_PATH, sizeof(char));
169
170 if (!path)
171 return NULL;
172
173 if (FAILED(SHGetFolderPathA(0, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path)))
174 {
175 free(path);
176 return NULL;
177 }
178
179#elif defined(__IOS__)
180 path = ios_get_data();
181#else
182 size_t size = 0;
183 char* home = NULL;
192 path = GetEnvAlloc("XDG_CONFIG_HOME");
193
194 if (path)
195 return path;
196
197 home = GetPath_HOME();
198
199 if (!home)
200 home = GetPath_TEMP();
201
202 if (!home)
203 return NULL;
204
205 size = strlen(home) + strlen("/.config") + 1;
206 path = (char*)malloc(size);
207
208 if (!path)
209 {
210 free(home);
211 return NULL;
212 }
213
214 (void)sprintf_s(path, size, "%s%s", home, "/.config");
215 free(home);
216#endif
217 return path;
218}
219
220static char* GetPath_SYSTEM_CONFIG_HOME(void)
221{
222 char* path = NULL;
223#if defined(WIN32) && !defined(_UWP)
224
225 WCHAR* wpath = NULL;
226 if (FAILED(SHGetKnownFolderPath(&FOLDERID_ProgramData, 0, (HANDLE)-1, &wpath)))
227 return NULL;
228
229 if (wpath)
230 path = ConvertWCharToUtf8Alloc(wpath, NULL);
231 CoTaskMemFree(wpath);
232
233#elif defined(__IOS__)
234 path = ios_get_data();
235#else
236 path = _strdup(WINPR_INSTALL_SYSCONFDIR);
237#endif
238 return path;
239}
240
241static char* GetPath_XDG_CACHE_HOME(void)
242{
243 char* path = NULL;
244#if defined(WIN32)
245 {
246 char* home = GetPath_XDG_RUNTIME_DIR();
247
248 if (home)
249 {
250 path = GetCombinedPath(home, "cache");
251
252 if (!winpr_PathFileExists(path))
253 if (!CreateDirectoryA(path, NULL))
254 path = NULL;
255 }
256
257 free(home);
258 }
259#elif defined(__IOS__)
260 path = ios_get_cache();
261#else
262 size_t size = 0;
271 path = GetEnvAlloc("XDG_CACHE_HOME");
272
273 if (path)
274 return path;
275
276 char* home = GetPath_HOME();
277
278 if (!home)
279 return NULL;
280
281 size = strlen(home) + strlen("/.cache") + 1;
282 path = (char*)malloc(size);
283
284 if (!path)
285 {
286 free(home);
287 return NULL;
288 }
289
290 (void)sprintf_s(path, size, "%s%s", home, "/.cache");
291 free(home);
292#endif
293 return path;
294}
295
296char* GetPath_XDG_RUNTIME_DIR(void)
297{
298 char* path = NULL;
299#if defined(WIN32) && !defined(_UWP)
300 path = calloc(MAX_PATH, sizeof(char));
301
302 if (!path)
303 return NULL;
304
305 if (FAILED(SHGetFolderPathA(0, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path)))
306 {
307 free(path);
308 return NULL;
309 }
310
311#else
343 path = GetEnvAlloc("XDG_RUNTIME_DIR");
344#endif
345
346 if (path)
347 return path;
348
349 path = GetPath_TEMP();
350 return path;
351}
352
353char* GetKnownPath(eKnownPathTypes id)
354{
355 char* path = NULL;
356
357 switch (id)
358 {
359 case KNOWN_PATH_HOME:
360 path = GetPath_HOME();
361 break;
362
363 case KNOWN_PATH_TEMP:
364 path = GetPath_TEMP();
365 break;
366
367 case KNOWN_PATH_XDG_DATA_HOME:
368 path = GetPath_XDG_DATA_HOME();
369 break;
370
371 case KNOWN_PATH_XDG_CONFIG_HOME:
372 path = GetPath_XDG_CONFIG_HOME();
373 break;
374
375 case KNOWN_PATH_XDG_CACHE_HOME:
376 path = GetPath_XDG_CACHE_HOME();
377 break;
378
379 case KNOWN_PATH_XDG_RUNTIME_DIR:
380 path = GetPath_XDG_RUNTIME_DIR();
381 break;
382
383 case KNOWN_PATH_SYSTEM_CONFIG_HOME:
384 path = GetPath_SYSTEM_CONFIG_HOME();
385 break;
386
387 default:
388 path = NULL;
389 break;
390 }
391
392 if (!path)
393 WLog_WARN(TAG, "Path %s is %p", GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(int, id)),
394 path);
395 return path;
396}
397
398char* GetKnownSubPath(eKnownPathTypes id, const char* path)
399{
400 char* knownPath = GetKnownPath(id);
401 if (!knownPath)
402 return NULL;
403
404 char* subPath = GetCombinedPath(knownPath, path);
405 free(knownPath);
406 return subPath;
407}
408
409char* GetEnvironmentPath(char* name)
410{
411 char* env = NULL;
412 DWORD nSize = 0;
413 DWORD nStatus = 0;
414 nSize = GetEnvironmentVariableX(name, NULL, 0);
415
416 if (nSize)
417 {
418 env = (LPSTR)malloc(nSize);
419
420 if (!env)
421 return NULL;
422
423 nStatus = GetEnvironmentVariableX(name, env, nSize);
424
425 if (nStatus != (nSize - 1))
426 {
427 free(env);
428 return NULL;
429 }
430 }
431
432 return env;
433}
434
435char* GetEnvironmentSubPath(char* name, const char* path)
436{
437 char* env = NULL;
438 char* subpath = NULL;
439 env = GetEnvironmentPath(name);
440
441 if (!env)
442 return NULL;
443
444 subpath = GetCombinedPath(env, path);
445 free(env);
446 return subpath;
447}
448
449char* GetCombinedPath(const char* basePath, const char* subPath)
450{
451 size_t length = 0;
452 HRESULT status = 0;
453 char* path = NULL;
454 char* subPathCpy = NULL;
455 size_t basePathLength = 0;
456 size_t subPathLength = 0;
457
458 if (basePath)
459 basePathLength = strlen(basePath);
460
461 if (subPath)
462 subPathLength = strlen(subPath);
463
464 length = basePathLength + subPathLength + 1;
465 path = (char*)calloc(1, length + 1);
466
467 if (!path)
468 goto fail;
469
470 if (basePath)
471 CopyMemory(path, basePath, basePathLength);
472
473 if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
474 goto fail;
475
476 if (!subPath)
477 return path;
478
479 subPathCpy = _strdup(subPath);
480
481 if (!subPathCpy)
482 goto fail;
483
484 if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
485 goto fail;
486
487 status = NativePathCchAppendA(path, length + 1, subPathCpy);
488 if (FAILED(status))
489 goto fail;
490
491 free(subPathCpy);
492 return path;
493
494fail:
495 free(path);
496 free(subPathCpy);
497 return NULL;
498}
499
500BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
501{
502#if defined(_UWP)
503 return FALSE;
504#elif defined(_WIN32)
505 return (SHCreateDirectoryExA(NULL, path, lpAttributes) == ERROR_SUCCESS);
506#else
507 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
508 char* dup = NULL;
509 BOOL result = TRUE;
510 /* we only operate on a non-null, absolute path */
511#if defined(__OS2__)
512
513 if (!path)
514 return FALSE;
515
516#else
517
518 if (!path || *path != delim)
519 return FALSE;
520
521#endif
522
523 if (!(dup = _strdup(path)))
524 return FALSE;
525
526#ifdef __OS2__
527 p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
528
529 while (p)
530#else
531 for (char* p = dup; p;)
532#endif
533 {
534 if ((p = strchr(p + 1, delim)))
535 *p = '\0';
536
537 if (mkdir(dup, 0777) != 0)
538 if (errno != EEXIST)
539 {
540 result = FALSE;
541 break;
542 }
543
544 if (p)
545 *p = delim;
546 }
547
548 free(dup);
549 return (result);
550#endif
551}
552
553BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
554{
555#if defined(_UWP)
556 return FALSE;
557#elif defined(_WIN32)
558 return (SHCreateDirectoryExW(NULL, path, lpAttributes) == ERROR_SUCCESS);
559#else
560 const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
561 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
562 char* dup = NULL;
563 BOOL result = TRUE;
564 /* we only operate on a non-null, absolute path */
565#if defined(__OS2__)
566
567 if (!path)
568 return FALSE;
569
570#else
571
572 if (!path || *path != wdelim)
573 return FALSE;
574
575#endif
576
577 dup = ConvertWCharToUtf8Alloc(path, NULL);
578 if (!dup)
579 return FALSE;
580
581#ifdef __OS2__
582 p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
583
584 while (p)
585#else
586 for (char* p = dup; p;)
587#endif
588 {
589 if ((p = strchr(p + 1, delim)))
590 *p = '\0';
591
592 if (mkdir(dup, 0777) != 0)
593 if (errno != EEXIST)
594 {
595 result = FALSE;
596 break;
597 }
598
599 if (p)
600 *p = delim;
601 }
602
603 free(dup);
604 return (result);
605#endif
606}
607
608#if !defined(_WIN32) || defined(_UWP)
609
610BOOL PathIsRelativeA(LPCSTR pszPath)
611{
612 if (!pszPath)
613 return FALSE;
614
615 return pszPath[0] != '/';
616}
617
618BOOL PathIsRelativeW(LPCWSTR pszPath)
619{
620 LPSTR lpFileNameA = NULL;
621 BOOL ret = FALSE;
622
623 if (!pszPath)
624 goto fail;
625
626 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
627 if (!lpFileNameA)
628 goto fail;
629 ret = PathIsRelativeA(lpFileNameA);
630fail:
631 free(lpFileNameA);
632 return ret;
633}
634
635BOOL PathFileExistsA(LPCSTR pszPath)
636{
637 struct stat stat_info;
638
639 if (stat(pszPath, &stat_info) != 0)
640 return FALSE;
641
642 return TRUE;
643}
644
645BOOL PathFileExistsW(LPCWSTR pszPath)
646{
647 LPSTR lpFileNameA = NULL;
648 BOOL ret = FALSE;
649
650 if (!pszPath)
651 goto fail;
652 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
653 if (!lpFileNameA)
654 goto fail;
655
656 ret = winpr_PathFileExists(lpFileNameA);
657fail:
658 free(lpFileNameA);
659 return ret;
660}
661
662BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
663{
664 struct dirent* dp = NULL;
665 int empty = 1;
666 DIR* dir = opendir(pszPath);
667
668 if (dir == NULL) /* Not a directory or doesn't exist */
669 return 1;
670
671 // NOLINTNEXTLINE(concurrency-mt-unsafe)
672 while ((dp = readdir(dir)) != NULL)
673 {
674 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
675 continue; /* Skip . and .. */
676
677 empty = 0;
678 break;
679 }
680
681 closedir(dir);
682 return empty;
683}
684
685BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
686{
687 LPSTR lpFileNameA = NULL;
688 BOOL ret = FALSE;
689 if (!pszPath)
690 goto fail;
691 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
692 if (!lpFileNameA)
693 goto fail;
694 ret = PathIsDirectoryEmptyA(lpFileNameA);
695fail:
696 free(lpFileNameA);
697 return ret;
698}
699
700#endif
701
702BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
703{
704#ifndef _WIN32
705 return MoveFileA(lpExistingFileName, lpNewFileName);
706#else
707 BOOL result = FALSE;
708 LPWSTR lpExistingFileNameW = NULL;
709 LPWSTR lpNewFileNameW = NULL;
710
711 if (!lpExistingFileName || !lpNewFileName)
712 return FALSE;
713
714 lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName, NULL);
715 if (!lpExistingFileNameW)
716 goto cleanup;
717 lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName, NULL);
718 if (!lpNewFileNameW)
719 goto cleanup;
720
721 result = MoveFileW(lpExistingFileNameW, lpNewFileNameW);
722
723cleanup:
724 free(lpExistingFileNameW);
725 free(lpNewFileNameW);
726 return result;
727#endif
728}
729
730BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
731{
732#ifndef _WIN32
733 return MoveFileExA(lpExistingFileName, lpNewFileName, dwFlags);
734#else
735 BOOL result = FALSE;
736 LPWSTR lpExistingFileNameW = NULL;
737 LPWSTR lpNewFileNameW = NULL;
738
739 if (!lpExistingFileName || !lpNewFileName)
740 return FALSE;
741
742 lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName, NULL);
743 if (!lpExistingFileNameW)
744 goto cleanup;
745 lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName, NULL);
746 if (!lpNewFileNameW)
747 goto cleanup;
748
749 result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, dwFlags);
750
751cleanup:
752 free(lpExistingFileNameW);
753 free(lpNewFileNameW);
754 return result;
755#endif
756}
757
758BOOL winpr_DeleteFile(const char* lpFileName)
759{
760#ifndef _WIN32
761 return DeleteFileA(lpFileName);
762#else
763 LPWSTR lpFileNameW = NULL;
764 BOOL result = FALSE;
765
766 if (lpFileName)
767 {
768 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
769 if (!lpFileNameW)
770 goto cleanup;
771 }
772
773 result = DeleteFileW(lpFileNameW);
774
775cleanup:
776 free(lpFileNameW);
777 return result;
778#endif
779}
780
781BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
782{
783#ifndef _WIN32
784 return RemoveDirectoryA(lpPathName);
785#else
786 LPWSTR lpPathNameW = NULL;
787 BOOL result = FALSE;
788
789 if (lpPathName)
790 {
791 lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName, NULL);
792 if (!lpPathNameW)
793 goto cleanup;
794 }
795
796 result = RemoveDirectoryW(lpPathNameW);
797
798cleanup:
799 free(lpPathNameW);
800 return result;
801#endif
802}
803
804BOOL winpr_PathFileExists(const char* pszPath)
805{
806 if (!pszPath)
807 return FALSE;
808#ifndef _WIN32
809 return PathFileExistsA(pszPath);
810#else
811 WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath, NULL);
812 BOOL result = FALSE;
813
814 if (!pathW)
815 return FALSE;
816
817 result = PathFileExistsW(pathW);
818 free(pathW);
819
820 return result;
821#endif
822}
823
824BOOL winpr_PathMakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
825{
826 if (!path)
827 return FALSE;
828#ifndef _WIN32
829 return PathMakePathA(path, lpAttributes);
830#else
831 WCHAR* pathW = ConvertUtf8ToWCharAlloc(path, NULL);
832 BOOL result = FALSE;
833
834 if (!pathW)
835 return FALSE;
836
837 result = SHCreateDirectoryExW(NULL, pathW, lpAttributes) == ERROR_SUCCESS;
838 free(pathW);
839
840 return result;
841#endif
842}