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