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 %p", GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(int, id)),
392 path);
393 return path;
394}
395
396char* GetKnownSubPath(eKnownPathTypes id, const char* path)
397{
398 char* knownPath = GetKnownPath(id);
399 if (!knownPath)
400 return NULL;
401
402 char* subPath = GetCombinedPath(knownPath, path);
403 free(knownPath);
404 return subPath;
405}
406
407char* GetEnvironmentPath(char* name)
408{
409 char* env = NULL;
410 DWORD nSize = 0;
411 DWORD nStatus = 0;
412 nSize = GetEnvironmentVariableX(name, NULL, 0);
413
414 if (nSize)
415 {
416 env = (LPSTR)malloc(nSize);
417
418 if (!env)
419 return NULL;
420
421 nStatus = GetEnvironmentVariableX(name, env, nSize);
422
423 if (nStatus != (nSize - 1))
424 {
425 free(env);
426 return NULL;
427 }
428 }
429
430 return env;
431}
432
433char* GetEnvironmentSubPath(char* name, const char* path)
434{
435 char* env = NULL;
436 char* subpath = NULL;
437 env = GetEnvironmentPath(name);
438
439 if (!env)
440 return NULL;
441
442 subpath = GetCombinedPath(env, path);
443 free(env);
444 return subpath;
445}
446
447char* GetCombinedPath(const char* basePath, const char* subPath)
448{
449 HRESULT status = 0;
450 char* subPathCpy = NULL;
451 size_t basePathLength = 0;
452 size_t subPathLength = 0;
453
454 if (basePath)
455 basePathLength = strlen(basePath);
456
457 if (subPath)
458 subPathLength = strlen(subPath);
459
460 const size_t length = basePathLength + subPathLength + 1;
461 char* path = (char*)calloc(1, length + 1);
462
463 if (!path)
464 goto fail;
465
466 if (basePath)
467 CopyMemory(path, basePath, basePathLength);
468
469 if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
470 goto fail;
471
472 if (!subPath)
473 return path;
474
475 subPathCpy = _strdup(subPath);
476
477 if (!subPathCpy)
478 goto fail;
479
480 if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
481 goto fail;
482
483 status = NativePathCchAppendA(path, length + 1, subPathCpy);
484 if (FAILED(status))
485 goto fail;
486
487 free(subPathCpy);
488 return path;
489
490fail:
491 free(path);
492 free(subPathCpy);
493 return NULL;
494}
495
496BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
497{
498#if defined(_UWP)
499 return FALSE;
500#elif defined(_WIN32)
501 return (SHCreateDirectoryExA(NULL, path, lpAttributes) == ERROR_SUCCESS);
502#else
503 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
504 char* dup = NULL;
505 BOOL result = TRUE;
506 /* we only operate on a non-null, absolute path */
507#if defined(__OS2__)
508
509 if (!path)
510 return FALSE;
511
512#else
513
514 if (!path || *path != delim)
515 return FALSE;
516
517#endif
518
519 if (!(dup = _strdup(path)))
520 return FALSE;
521
522#ifdef __OS2__
523 p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
524
525 while (p)
526#else
527 for (char* p = dup; p;)
528#endif
529 {
530 if ((p = strchr(p + 1, delim)))
531 *p = '\0';
532
533 if (mkdir(dup, 0777) != 0)
534 if (errno != EEXIST)
535 {
536 result = FALSE;
537 break;
538 }
539
540 if (p)
541 *p = delim;
542 }
543
544 free(dup);
545 return (result);
546#endif
547}
548
549BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
550{
551#if defined(_UWP)
552 return FALSE;
553#elif defined(_WIN32)
554 return (SHCreateDirectoryExW(NULL, path, lpAttributes) == ERROR_SUCCESS);
555#else
556 const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
557 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
558 char* dup = NULL;
559 BOOL result = TRUE;
560 /* we only operate on a non-null, absolute path */
561#if defined(__OS2__)
562
563 if (!path)
564 return FALSE;
565
566#else
567
568 if (!path || *path != wdelim)
569 return FALSE;
570
571#endif
572
573 dup = ConvertWCharToUtf8Alloc(path, NULL);
574 if (!dup)
575 return FALSE;
576
577#ifdef __OS2__
578 p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
579
580 while (p)
581#else
582 for (char* p = dup; p;)
583#endif
584 {
585 if ((p = strchr(p + 1, delim)))
586 *p = '\0';
587
588 if (mkdir(dup, 0777) != 0)
589 if (errno != EEXIST)
590 {
591 result = FALSE;
592 break;
593 }
594
595 if (p)
596 *p = delim;
597 }
598
599 free(dup);
600 return (result);
601#endif
602}
603
604#if !defined(_WIN32) || defined(_UWP)
605
606BOOL PathIsRelativeA(LPCSTR pszPath)
607{
608 if (!pszPath)
609 return FALSE;
610
611 return pszPath[0] != '/';
612}
613
614BOOL PathIsRelativeW(LPCWSTR pszPath)
615{
616 LPSTR lpFileNameA = NULL;
617 BOOL ret = FALSE;
618
619 if (!pszPath)
620 goto fail;
621
622 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
623 if (!lpFileNameA)
624 goto fail;
625 ret = PathIsRelativeA(lpFileNameA);
626fail:
627 free(lpFileNameA);
628 return ret;
629}
630
631BOOL PathFileExistsA(LPCSTR pszPath)
632{
633 struct stat stat_info;
634
635 if (stat(pszPath, &stat_info) != 0)
636 return FALSE;
637
638 return TRUE;
639}
640
641BOOL PathFileExistsW(LPCWSTR pszPath)
642{
643 LPSTR lpFileNameA = NULL;
644 BOOL ret = FALSE;
645
646 if (!pszPath)
647 goto fail;
648 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
649 if (!lpFileNameA)
650 goto fail;
651
652 ret = winpr_PathFileExists(lpFileNameA);
653fail:
654 free(lpFileNameA);
655 return ret;
656}
657
658BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
659{
660 struct dirent* dp = NULL;
661 int empty = 1;
662 DIR* dir = opendir(pszPath);
663
664 if (dir == NULL) /* Not a directory or doesn't exist */
665 return 1;
666
667 // NOLINTNEXTLINE(concurrency-mt-unsafe)
668 while ((dp = readdir(dir)) != NULL)
669 {
670 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
671 continue; /* Skip . and .. */
672
673 empty = 0;
674 break;
675 }
676
677 closedir(dir);
678 return empty;
679}
680
681BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
682{
683 LPSTR lpFileNameA = NULL;
684 BOOL ret = FALSE;
685 if (!pszPath)
686 goto fail;
687 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
688 if (!lpFileNameA)
689 goto fail;
690 ret = PathIsDirectoryEmptyA(lpFileNameA);
691fail:
692 free(lpFileNameA);
693 return ret;
694}
695
696#endif
697
698BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
699{
700 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
701}
702
703BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
704{
705#ifndef _WIN32
706 struct stat st;
707 int ret = 0;
708 ret = stat(lpNewFileName, &st);
709
710 if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
711 {
712 if (ret == 0)
713 {
714 SetLastError(ERROR_ALREADY_EXISTS);
715 return FALSE;
716 }
717 }
718 else
719 {
720 if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
721 {
722 SetLastError(ERROR_ACCESS_DENIED);
723 return FALSE;
724 }
725 }
726
727 ret = rename(lpExistingFileName, lpNewFileName);
728
729 if (ret != 0)
730 SetLastError(map_posix_err(errno));
731
732 return ret == 0;
733#else
734 BOOL result = FALSE;
735 LPWSTR lpExistingFileNameW = NULL;
736 LPWSTR lpNewFileNameW = NULL;
737
738 if (!lpExistingFileName || !lpNewFileName)
739 return FALSE;
740
741 lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName, NULL);
742 if (!lpExistingFileNameW)
743 goto cleanup;
744 lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName, NULL);
745 if (!lpNewFileNameW)
746 goto cleanup;
747
748 result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, dwFlags);
749
750cleanup:
751 free(lpExistingFileNameW);
752 free(lpNewFileNameW);
753 return result;
754#endif
755}
756
757BOOL winpr_DeleteFile(const char* lpFileName)
758{
759#ifndef _WIN32
760 if (!lpFileName)
761 return FALSE;
762
763 const int status = unlink(lpFileName);
764 return (status != -1) ? TRUE : FALSE;
765#else
766 LPWSTR lpFileNameW = NULL;
767 BOOL result = FALSE;
768
769 if (lpFileName)
770 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
771
772 if (!lpFileNameW)
773 goto cleanup;
774
775 result = DeleteFileW(lpFileNameW);
776
777cleanup:
778 free(lpFileNameW);
779 return result;
780#endif
781}
782
783BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
784{
785#ifndef _WIN32
786 int ret = rmdir(lpPathName);
787
788 if (ret != 0)
789 SetLastError(map_posix_err(errno));
790 else
791 SetLastError(STATUS_SUCCESS);
792
793 return ret == 0;
794#else
795 LPWSTR lpPathNameW = NULL;
796 BOOL result = FALSE;
797
798 if (lpPathName)
799 lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName, NULL);
800
801 if (!lpPathNameW)
802 goto cleanup;
803
804 result = RemoveDirectoryW(lpPathNameW);
805
806cleanup:
807 free(lpPathNameW);
808 return result;
809#endif
810}
811
812BOOL winpr_PathFileExists(const char* pszPath)
813{
814 if (!pszPath)
815 return FALSE;
816#ifndef _WIN32
817 return PathFileExistsA(pszPath);
818#else
819 WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath, NULL);
820 BOOL result = FALSE;
821
822 if (!pathW)
823 return FALSE;
824
825 result = PathFileExistsW(pathW);
826 free(pathW);
827
828 return result;
829#endif
830}
831
832BOOL winpr_PathMakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
833{
834 if (!path)
835 return FALSE;
836#ifndef _WIN32
837 return PathMakePathA(path, lpAttributes);
838#else
839 WCHAR* pathW = ConvertUtf8ToWCharAlloc(path, NULL);
840 BOOL result = FALSE;
841
842 if (!pathW)
843 return FALSE;
844
845 result = SHCreateDirectoryExW(NULL, pathW, lpAttributes) == ERROR_SUCCESS;
846 free(pathW);
847
848 return result;
849#endif
850}