21#include <winpr/config.h>
22#include <winpr/build-config.h>
30#include <winpr/platform.h>
31#include <winpr/file.h>
32#include <winpr/tchar.h>
33#include <winpr/environment.h>
35#include <winpr/path.h>
36#include <winpr/wlog.h>
38#include "../file/file.h"
41#define TAG WINPR_TAG("path.shell")
55static char* GetPath_XDG_CONFIG_HOME(
void);
56static char* GetPath_XDG_RUNTIME_DIR(
void);
63#if defined(WIN32) && !defined(_UWP)
65static char* win_get_known_folder(REFKNOWNFOLDERID
id, BOOL currentUser)
67 WCHAR* wpath =
nullptr;
68 HANDLE handle = currentUser ? nullptr : (HANDLE)-1;
69 if (FAILED(SHGetKnownFolderPath(
id, 0, handle, &wpath)))
75 char* path = ConvertWCharToUtf8Alloc(wpath,
nullptr);
86char* GetEnvAlloc(LPCSTR lpName)
92 nSize = GetEnvironmentVariableX(lpName,
nullptr, 0);
101 nStatus = GetEnvironmentVariableX(lpName, env, nSize);
103 if (nStatus != (nSize - 1))
113static char* GetPath_HOME(
void)
115 char* path =
nullptr;
117 path = GetEnvAlloc(
"UserProfile");
118#elif defined(__IOS__)
119 path = ios_get_home();
121 path = GetEnvAlloc(
"HOME");
126static char* GetPath_TEMP(
void)
128 char* path =
nullptr;
130 path = GetEnvAlloc(
"TEMP");
131#elif defined(__IOS__)
132 path = ios_get_temp();
134 path = GetEnvAlloc(
"TMPDIR");
137 path = _strdup(
"/tmp");
143static char* GetPath_XDG_DATA_HOME(
void)
145 char* path =
nullptr;
146#if defined(WIN32) || defined(__IOS__)
147 path = GetPath_XDG_CONFIG_HOME();
150 char* home =
nullptr;
159 path = GetEnvAlloc(
"XDG_DATA_HOME");
164 home = GetPath_HOME();
169 size = strlen(home) + strlen(
"/.local/share") + 1;
170 path = (
char*)malloc(size);
178 (void)sprintf_s(path, size,
"%s%s", home,
"/.local/share");
184static char* GetPath_XDG_CONFIG_HOME(
void)
186 char* path =
nullptr;
187#if defined(WIN32) && !defined(_UWP)
189 path = win_get_known_folder(&FOLDERID_RoamingAppData, TRUE);
191#elif defined(__IOS__)
192 path = ios_get_data();
195 char* home =
nullptr;
204 path = GetEnvAlloc(
"XDG_CONFIG_HOME");
209 home = GetPath_HOME();
212 home = GetPath_TEMP();
217 size = strlen(home) + strlen(
"/.config") + 1;
218 path = (
char*)malloc(size);
226 (void)sprintf_s(path, size,
"%s%s", home,
"/.config");
232static char* GetPath_SYSTEM_CONFIG_HOME(
void)
234 char* path =
nullptr;
235#if defined(WIN32) && !defined(_UWP)
237 path = win_get_known_folder(&FOLDERID_ProgramData, FALSE);
239#elif defined(__IOS__)
240 path = ios_get_data();
242 path = _strdup(WINPR_INSTALL_SYSCONFDIR);
247static char* GetPath_XDG_CACHE_HOME(
void)
249 char* path =
nullptr;
252 char* home = GetPath_XDG_RUNTIME_DIR();
256 path = GetCombinedPath(home,
"cache");
258 if (!winpr_PathFileExists(path))
259 if (!winpr_PathMakePath(path,
nullptr))
265#elif defined(__IOS__)
266 path = ios_get_cache();
277 path = GetEnvAlloc(
"XDG_CACHE_HOME");
282 char* home = GetPath_HOME();
287 size = strlen(home) + strlen(
"/.cache") + 1;
288 path = (
char*)malloc(size);
296 (void)sprintf_s(path, size,
"%s%s", home,
"/.cache");
302char* GetPath_XDG_RUNTIME_DIR(
void)
304 char* path =
nullptr;
305#if defined(WIN32) && !defined(_UWP)
307 path = win_get_known_folder(&FOLDERID_LocalAppData, TRUE);
341 path = GetEnvAlloc(
"XDG_RUNTIME_DIR");
347 path = GetPath_TEMP();
351char* GetKnownPath(eKnownPathTypes
id)
353 char* path =
nullptr;
357 case KNOWN_PATH_HOME:
358 path = GetPath_HOME();
361 case KNOWN_PATH_TEMP:
362 path = GetPath_TEMP();
365 case KNOWN_PATH_XDG_DATA_HOME:
366 path = GetPath_XDG_DATA_HOME();
369 case KNOWN_PATH_XDG_CONFIG_HOME:
370 path = GetPath_XDG_CONFIG_HOME();
373 case KNOWN_PATH_XDG_CACHE_HOME:
374 path = GetPath_XDG_CACHE_HOME();
377 case KNOWN_PATH_XDG_RUNTIME_DIR:
378 path = GetPath_XDG_RUNTIME_DIR();
381 case KNOWN_PATH_SYSTEM_CONFIG_HOME:
382 path = GetPath_SYSTEM_CONFIG_HOME();
391 WLog_WARN(TAG,
"Path %s is nullptr",
392 GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(
int,
id)));
396char* GetKnownSubPath(eKnownPathTypes
id,
const char* path)
399 return GetKnownSubPathV(
id,
"%s",
"");
400 return GetKnownSubPathV(
id,
"%s", path);
403char* GetKnownSubPathV(eKnownPathTypes
id,
const char* path, ...)
405 va_list ap = WINPR_C_ARRAY_INIT;
408 char* str = GetKnownSubPathVA(
id, path, ap);
413char* GetKnownSubPathVA(eKnownPathTypes
id,
const char* path, va_list ap)
415 char* knownPath = GetKnownPath(
id);
419 char* subPath = GetCombinedPathVA(knownPath, path, ap);
424char* GetEnvironmentPath(
char* name)
429 nSize = GetEnvironmentVariableX(name,
nullptr, 0);
433 env = (LPSTR)malloc(nSize);
438 nStatus = GetEnvironmentVariableX(name, env, nSize);
440 if (nStatus != (nSize - 1))
450char* GetEnvironmentSubPath(
char* name,
const char* path)
453 return GetEnvironmentSubPathV(name,
"%s",
"");
454 return GetEnvironmentSubPathV(name,
"%s", path);
457char* GetEnvironmentSubPathV(
char* name,
const char* path, ...)
459 va_list ap = WINPR_C_ARRAY_INIT;
461 char* str = GetEnvironmentSubPathVA(name, path, ap);
466char* GetEnvironmentSubPathVA(
char* name, WINPR_FORMAT_ARG
const char* path, va_list ap)
468 char* env = GetEnvironmentPath(name);
473 char* subpath = GetCombinedPathVA(env, path, ap);
478char* GetCombinedPath(
const char* basePath,
const char* subPathFmt)
481 return GetCombinedPathV(basePath,
"%s",
"");
482 return GetCombinedPathV(basePath,
"%s", subPathFmt);
485char* GetCombinedPathV(
const char* basePath,
const char* subPathFmt, ...)
487 va_list ap = WINPR_C_ARRAY_INIT;
489 va_start(ap, subPathFmt);
490 char* str = GetCombinedPathVA(basePath, subPathFmt, ap);
495char* GetCombinedPathVA(
const char* basePath, WINPR_FORMAT_ARG
const char* subPathFmt, va_list ap)
498 char* subPathCpy =
nullptr;
499 size_t basePathLength = 0;
500 size_t subPathLength = 0;
503 basePathLength = strlen(basePath);
505 bool haveSubPath = subPathFmt && (*subPathFmt !=
'\0');
508 const int rc = winpr_vasprintf(&subPathCpy, &subPathLength, subPathFmt, ap);
514 subPathCpy =
nullptr;
520 const size_t length = basePathLength + subPathLength + 1;
521 char* path = (
char*)calloc(1, length + 1);
527 CopyMemory(path, basePath, basePathLength);
529 if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
538 if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
541 status = NativePathCchAppendA(path, length + 1, subPathCpy);
554BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
559 return (SHCreateDirectoryExA(
nullptr, path, lpAttributes) == ERROR_SUCCESS);
561 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
572 if (!path || *path != delim)
577 if (!(dup = _strdup(path)))
581 p = (strlen(dup) > 3) && (dup[1] ==
':') && (dup[2] == delim)) ? &dup[3] : dup;
585 for (
char* p = dup; p;)
588 if ((p = strchr(p + 1, delim)))
591 if (mkdir(dup, 0777) != 0)
607BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
612 return (SHCreateDirectoryExW(
nullptr, path, lpAttributes) == ERROR_SUCCESS);
614 const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
615 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
626 if (!path || *path != wdelim)
631 dup = ConvertWCharToUtf8Alloc(path,
nullptr);
636 p = (strlen(dup) > 3) && (dup[1] ==
':') && (dup[2] == delim)) ? &dup[3] : dup;
640 for (
char* p = dup; p;)
643 if ((p = strchr(p + 1, delim)))
646 if (mkdir(dup, 0777) != 0)
662#if !defined(_WIN32) || defined(_UWP)
664BOOL PathIsRelativeA(LPCSTR pszPath)
669 return pszPath[0] !=
'/';
672BOOL PathIsRelativeW(LPCWSTR pszPath)
674 LPSTR lpFileNameA =
nullptr;
680 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath,
nullptr);
683 ret = PathIsRelativeA(lpFileNameA);
689BOOL PathFileExistsA(LPCSTR pszPath)
691 struct stat stat_info;
693 return (stat(pszPath, &stat_info) == 0);
696BOOL PathFileExistsW(LPCWSTR pszPath)
698 LPSTR lpFileNameA =
nullptr;
703 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath,
nullptr);
707 ret = winpr_PathFileExists(lpFileNameA);
713BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
715 struct dirent* dp =
nullptr;
717 DIR* dir = opendir(pszPath);
723 while ((dp = readdir(dir)) !=
nullptr)
725 if (strcmp(dp->d_name,
".") == 0 || strcmp(dp->d_name,
"..") == 0)
736BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
738 LPSTR lpFileNameA =
nullptr;
742 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath,
nullptr);
745 ret = PathIsDirectoryEmptyA(lpFileNameA);
753BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
755 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
758BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
763 ret = stat(lpNewFileName, &st);
765 if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
769 SetLastError(ERROR_ALREADY_EXISTS);
775 if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
777 SetLastError(ERROR_ACCESS_DENIED);
782 ret = rename(lpExistingFileName, lpNewFileName);
785 SetLastError(map_posix_err(errno));
790 LPWSTR lpExistingFileNameW =
nullptr;
791 LPWSTR lpNewFileNameW =
nullptr;
793 if (!lpExistingFileName || !lpNewFileName)
796 lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName,
nullptr);
797 if (!lpExistingFileNameW)
799 lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName,
nullptr);
803 result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, dwFlags);
806 free(lpExistingFileNameW);
807 free(lpNewFileNameW);
812BOOL winpr_DeleteFile(
const char* lpFileName)
818 const int status = unlink(lpFileName);
819 return (status != -1);
821 LPWSTR lpFileNameW =
nullptr;
825 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
830 result = DeleteFileW(lpFileNameW);
838BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
841 int ret = rmdir(lpPathName);
844 SetLastError(map_posix_err(errno));
846 SetLastError(STATUS_SUCCESS);
850 LPWSTR lpPathNameW =
nullptr;
854 lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName,
nullptr);
859 result = RemoveDirectoryW(lpPathNameW);
867BOOL winpr_PathFileExists(
const char* pszPath)
872 return PathFileExistsA(pszPath);
874 WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath,
nullptr);
880 result = PathFileExistsW(pathW);
887BOOL winpr_PathMakePath(
const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
892 return PathMakePathA(path, lpAttributes);
894 WCHAR* pathW = ConvertUtf8ToWCharAlloc(path,
nullptr);
900 result = SHCreateDirectoryExW(
nullptr, pathW, lpAttributes) == ERROR_SUCCESS;