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")
56static char* GetPath_XDG_CONFIG_HOME(
void);
57static char* GetPath_XDG_RUNTIME_DIR(
void);
64#if defined(WIN32) && !defined(_UWP)
66static char* win_get_known_folder(REFKNOWNFOLDERID
id, BOOL currentUser)
68 WCHAR* wpath =
nullptr;
69 HANDLE handle = currentUser ? nullptr : (HANDLE)-1;
70 if (FAILED(SHGetKnownFolderPath(
id, 0, handle, &wpath)))
76 char* path = ConvertWCharToUtf8Alloc(wpath,
nullptr);
87char* GetEnvAlloc(LPCSTR lpName)
93 nSize = GetEnvironmentVariableX(lpName,
nullptr, 0);
102 nStatus = GetEnvironmentVariableX(lpName, env, nSize);
104 if (nStatus != (nSize - 1))
114static char* GetPath_HOME(
void)
116 char* path =
nullptr;
118 path = GetEnvAlloc(
"UserProfile");
119#elif defined(__IOS__)
120 path = ios_get_home();
122 path = GetEnvAlloc(
"HOME");
127static char* GetPath_TEMP(
void)
129 char* path =
nullptr;
131 path = GetEnvAlloc(
"TEMP");
132#elif defined(__IOS__)
133 path = ios_get_temp();
135 path = GetEnvAlloc(
"TMPDIR");
138 path = _strdup(
"/tmp");
144static char* GetPath_XDG_DATA_HOME(
void)
146 char* path =
nullptr;
147#if defined(WIN32) || defined(__IOS__)
148 path = GetPath_XDG_CONFIG_HOME();
151 char* home =
nullptr;
160 path = GetEnvAlloc(
"XDG_DATA_HOME");
165 home = GetPath_HOME();
170 size = strlen(home) + strlen(
"/.local/share") + 1;
171 path = (
char*)malloc(size);
179 (void)sprintf_s(path, size,
"%s%s", home,
"/.local/share");
185static char* GetPath_XDG_CONFIG_HOME(
void)
187 char* path =
nullptr;
188#if defined(WIN32) && !defined(_UWP)
190 path = win_get_known_folder(&FOLDERID_RoamingAppData, TRUE);
192#elif defined(__IOS__)
193 path = ios_get_data();
196 char* home =
nullptr;
205 path = GetEnvAlloc(
"XDG_CONFIG_HOME");
210 home = GetPath_HOME();
213 home = GetPath_TEMP();
218 size = strlen(home) + strlen(
"/.config") + 1;
219 path = (
char*)malloc(size);
227 (void)sprintf_s(path, size,
"%s%s", home,
"/.config");
233static char* GetPath_SYSTEM_CONFIG_HOME(
void)
235 char* path =
nullptr;
236#if defined(WIN32) && !defined(_UWP)
238 path = win_get_known_folder(&FOLDERID_ProgramData, FALSE);
240#elif defined(__IOS__)
241 path = ios_get_data();
243 path = _strdup(WINPR_INSTALL_SYSCONFDIR);
248static char* GetPath_XDG_CACHE_HOME(
void)
250 char* path =
nullptr;
253 char* home = GetPath_XDG_RUNTIME_DIR();
257 path = GetCombinedPath(home,
"cache");
259 if (!winpr_PathFileExists(path))
260 if (!winpr_PathMakePath(path,
nullptr))
266#elif defined(__IOS__)
267 path = ios_get_cache();
278 path = GetEnvAlloc(
"XDG_CACHE_HOME");
283 char* home = GetPath_HOME();
288 size = strlen(home) + strlen(
"/.cache") + 1;
289 path = (
char*)malloc(size);
297 (void)sprintf_s(path, size,
"%s%s", home,
"/.cache");
303char* GetPath_XDG_RUNTIME_DIR(
void)
305 char* path =
nullptr;
306#if defined(WIN32) && !defined(_UWP)
308 path = win_get_known_folder(&FOLDERID_LocalAppData, TRUE);
342 path = GetEnvAlloc(
"XDG_RUNTIME_DIR");
348 path = GetPath_TEMP();
352char* GetKnownPath(eKnownPathTypes
id)
354 char* path =
nullptr;
358 case KNOWN_PATH_HOME:
359 path = GetPath_HOME();
362 case KNOWN_PATH_TEMP:
363 path = GetPath_TEMP();
366 case KNOWN_PATH_XDG_DATA_HOME:
367 path = GetPath_XDG_DATA_HOME();
370 case KNOWN_PATH_XDG_CONFIG_HOME:
371 path = GetPath_XDG_CONFIG_HOME();
374 case KNOWN_PATH_XDG_CACHE_HOME:
375 path = GetPath_XDG_CACHE_HOME();
378 case KNOWN_PATH_XDG_RUNTIME_DIR:
379 path = GetPath_XDG_RUNTIME_DIR();
382 case KNOWN_PATH_SYSTEM_CONFIG_HOME:
383 path = GetPath_SYSTEM_CONFIG_HOME();
392 WLog_WARN(TAG,
"Path %s is nullptr",
393 GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(
int,
id)));
397char* GetKnownSubPath(eKnownPathTypes
id,
const char* path)
400 return GetKnownSubPathV(
id,
"%s",
"");
401 return GetKnownSubPathV(
id,
"%s", path);
404char* GetKnownSubPathV(eKnownPathTypes
id,
const char* path, ...)
406 va_list ap = WINPR_C_ARRAY_INIT;
409 char* str = GetKnownSubPathVA(
id, path, ap);
414char* GetKnownSubPathVA(eKnownPathTypes
id,
const char* path, va_list ap)
416 char* knownPath = GetKnownPath(
id);
420 char* subPath = GetCombinedPathVA(knownPath, path, ap);
425char* GetEnvironmentPath(
char* name)
430 nSize = GetEnvironmentVariableX(name,
nullptr, 0);
434 env = (LPSTR)malloc(nSize);
439 nStatus = GetEnvironmentVariableX(name, env, nSize);
441 if (nStatus != (nSize - 1))
451char* GetEnvironmentSubPath(
char* name,
const char* path)
454 return GetEnvironmentSubPathV(name,
"%s",
"");
455 return GetEnvironmentSubPathV(name,
"%s", path);
458char* GetEnvironmentSubPathV(
char* name,
const char* path, ...)
460 va_list ap = WINPR_C_ARRAY_INIT;
462 char* str = GetEnvironmentSubPathVA(name, path, ap);
467char* GetEnvironmentSubPathVA(
char* name, WINPR_FORMAT_ARG
const char* path, va_list ap)
469 char* env = GetEnvironmentPath(name);
474 char* subpath = GetCombinedPathVA(env, path, ap);
479char* GetCombinedPath(
const char* basePath,
const char* subPathFmt)
482 return GetCombinedPathV(basePath,
"%s",
"");
483 return GetCombinedPathV(basePath,
"%s", subPathFmt);
486char* GetCombinedPathV(
const char* basePath,
const char* subPathFmt, ...)
488 va_list ap = WINPR_C_ARRAY_INIT;
490 va_start(ap, subPathFmt);
491 char* str = GetCombinedPathVA(basePath, subPathFmt, ap);
496char* GetCombinedPathVA(
const char* basePath, WINPR_FORMAT_ARG
const char* subPathFmt, va_list ap)
499 char* subPathCpy =
nullptr;
500 size_t basePathLength = 0;
501 size_t subPathLength = 0;
504 basePathLength = strlen(basePath);
506 bool haveSubPath = subPathFmt && (*subPathFmt !=
'\0');
509 const int rc = winpr_vasprintf(&subPathCpy, &subPathLength, subPathFmt, ap);
515 subPathCpy =
nullptr;
521 const size_t length = basePathLength + subPathLength + 1;
522 char* path = (
char*)calloc(1, length + 1);
528 CopyMemory(path, basePath, basePathLength);
530 if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
539 if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
542 status = NativePathCchAppendA(path, length + 1, subPathCpy);
555BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
560 return (SHCreateDirectoryExA(
nullptr, path, lpAttributes) == ERROR_SUCCESS);
562 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
573 if (!path || *path != delim)
578 if (!(dup = _strdup(path)))
582 p = (strlen(dup) > 3) && (dup[1] ==
':') && (dup[2] == delim)) ? &dup[3] : dup;
586 for (
char* p = dup; p;)
589 if ((p = strchr(p + 1, delim)))
592 if (mkdir(dup, 0777) != 0)
608BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
613 return (SHCreateDirectoryExW(
nullptr, path, lpAttributes) == ERROR_SUCCESS);
615 const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
616 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
627 if (!path || *path != wdelim)
632 dup = ConvertWCharToUtf8Alloc(path,
nullptr);
637 p = (strlen(dup) > 3) && (dup[1] ==
':') && (dup[2] == delim)) ? &dup[3] : dup;
641 for (
char* p = dup; p;)
644 if ((p = strchr(p + 1, delim)))
647 if (mkdir(dup, 0777) != 0)
663#if !defined(_WIN32) || defined(_UWP)
665BOOL PathIsRelativeA(LPCSTR pszPath)
670 return pszPath[0] !=
'/';
673BOOL PathIsRelativeW(LPCWSTR pszPath)
675 LPSTR lpFileNameA =
nullptr;
681 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath,
nullptr);
684 ret = PathIsRelativeA(lpFileNameA);
690BOOL PathFileExistsA(LPCSTR pszPath)
692 struct stat stat_info = WINPR_C_ARRAY_INIT;
694 return (stat(pszPath, &stat_info) == 0);
697BOOL PathFileExistsW(LPCWSTR pszPath)
699 LPSTR lpFileNameA =
nullptr;
704 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath,
nullptr);
708 ret = winpr_PathFileExists(lpFileNameA);
714BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
716 struct dirent* dp =
nullptr;
718 DIR* dir = opendir(pszPath);
724 while ((dp = readdir(dir)) !=
nullptr)
726 if (strcmp(dp->d_name,
".") == 0 || strcmp(dp->d_name,
"..") == 0)
737BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
739 LPSTR lpFileNameA =
nullptr;
743 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath,
nullptr);
746 ret = PathIsDirectoryEmptyA(lpFileNameA);
754BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
756 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
759BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
764 ret = stat(lpNewFileName, &st);
766 if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
770 SetLastError(ERROR_ALREADY_EXISTS);
776 if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
778 SetLastError(ERROR_ACCESS_DENIED);
783 ret = rename(lpExistingFileName, lpNewFileName);
786 SetLastError(map_posix_err(errno));
791 LPWSTR lpExistingFileNameW =
nullptr;
792 LPWSTR lpNewFileNameW =
nullptr;
794 if (!lpExistingFileName || !lpNewFileName)
797 lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName,
nullptr);
798 if (!lpExistingFileNameW)
800 lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName,
nullptr);
804 result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, dwFlags);
807 free(lpExistingFileNameW);
808 free(lpNewFileNameW);
813BOOL winpr_DeleteFile(
const char* lpFileName)
819 const int status = unlink(lpFileName);
820 return (status != -1);
822 LPWSTR lpFileNameW =
nullptr;
826 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName,
nullptr);
831 result = DeleteFileW(lpFileNameW);
839BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
842 int ret = rmdir(lpPathName);
845 SetLastError(map_posix_err(errno));
847 SetLastError(STATUS_SUCCESS);
851 LPWSTR lpPathNameW =
nullptr;
855 lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName,
nullptr);
860 result = RemoveDirectoryW(lpPathNameW);
868BOOL winpr_PathFileExists(
const char* pszPath)
873 return PathFileExistsA(pszPath);
875 WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath,
nullptr);
881 result = PathFileExistsW(pathW);
888BOOL winpr_PathMakePath(
const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
893 return PathMakePathA(path, lpAttributes);
895 WCHAR* pathW = ConvertUtf8ToWCharAlloc(path,
nullptr);
901 result = SHCreateDirectoryExW(
nullptr, pathW, lpAttributes) == ERROR_SUCCESS;