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)
68 HANDLE handle = currentUser ? NULL : (HANDLE)-1;
69 if (FAILED(SHGetKnownFolderPath(
id, 0, handle, &wpath)))
75 char* path = ConvertWCharToUtf8Alloc(wpath, NULL);
86char* GetEnvAlloc(LPCSTR lpName)
92 nSize = GetEnvironmentVariableX(lpName, NULL, 0);
101 nStatus = GetEnvironmentVariableX(lpName, env, nSize);
103 if (nStatus != (nSize - 1))
113static char* GetPath_HOME(
void)
117 path = GetEnvAlloc(
"UserProfile");
118#elif defined(__IOS__)
119 path = ios_get_home();
121 path = GetEnvAlloc(
"HOME");
126static char* GetPath_TEMP(
void)
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)
146#if defined(WIN32) || defined(__IOS__)
147 path = GetPath_XDG_CONFIG_HOME();
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)
187#if defined(WIN32) && !defined(_UWP)
189 path = win_get_known_folder(&FOLDERID_RoamingAppData, TRUE);
191#elif defined(__IOS__)
192 path = ios_get_data();
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)
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)
252 char* home = GetPath_XDG_RUNTIME_DIR();
256 path = GetCombinedPath(home,
"cache");
258 if (!winpr_PathFileExists(path))
259 if (!winpr_PathMakePath(path, NULL))
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)
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)
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 %p", GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(
int,
id)),
396char* GetKnownSubPath(eKnownPathTypes
id,
const char* path)
398 char* knownPath = GetKnownPath(
id);
402 char* subPath = GetCombinedPath(knownPath, path);
407char* GetEnvironmentPath(
char* name)
412 nSize = GetEnvironmentVariableX(name, NULL, 0);
416 env = (LPSTR)malloc(nSize);
421 nStatus = GetEnvironmentVariableX(name, env, nSize);
423 if (nStatus != (nSize - 1))
433char* GetEnvironmentSubPath(
char* name,
const char* path)
436 char* subpath = NULL;
437 env = GetEnvironmentPath(name);
442 subpath = GetCombinedPath(env, path);
447char* GetCombinedPath(
const char* basePath,
const char* subPath)
450 char* subPathCpy = NULL;
451 size_t basePathLength = 0;
452 size_t subPathLength = 0;
455 basePathLength = strlen(basePath);
458 subPathLength = strlen(subPath);
460 const size_t length = basePathLength + subPathLength + 1;
461 char* path = (
char*)calloc(1, length + 1);
467 CopyMemory(path, basePath, basePathLength);
469 if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
475 subPathCpy = _strdup(subPath);
480 if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
483 status = NativePathCchAppendA(path, length + 1, subPathCpy);
496BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
501 return (SHCreateDirectoryExA(NULL, path, lpAttributes) == ERROR_SUCCESS);
503 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
514 if (!path || *path != delim)
519 if (!(dup = _strdup(path)))
523 p = (strlen(dup) > 3) && (dup[1] ==
':') && (dup[2] == delim)) ? &dup[3] : dup;
527 for (
char* p = dup; p;)
530 if ((p = strchr(p + 1, delim)))
533 if (mkdir(dup, 0777) != 0)
549BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
554 return (SHCreateDirectoryExW(NULL, path, lpAttributes) == ERROR_SUCCESS);
556 const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
557 const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
568 if (!path || *path != wdelim)
573 dup = ConvertWCharToUtf8Alloc(path, NULL);
578 p = (strlen(dup) > 3) && (dup[1] ==
':') && (dup[2] == delim)) ? &dup[3] : dup;
582 for (
char* p = dup; p;)
585 if ((p = strchr(p + 1, delim)))
588 if (mkdir(dup, 0777) != 0)
604#if !defined(_WIN32) || defined(_UWP)
606BOOL PathIsRelativeA(LPCSTR pszPath)
611 return pszPath[0] !=
'/';
614BOOL PathIsRelativeW(LPCWSTR pszPath)
616 LPSTR lpFileNameA = NULL;
622 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
625 ret = PathIsRelativeA(lpFileNameA);
631BOOL PathFileExistsA(LPCSTR pszPath)
633 struct stat stat_info;
635 if (stat(pszPath, &stat_info) != 0)
641BOOL PathFileExistsW(LPCWSTR pszPath)
643 LPSTR lpFileNameA = NULL;
648 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
652 ret = winpr_PathFileExists(lpFileNameA);
658BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
660 struct dirent* dp = NULL;
662 DIR* dir = opendir(pszPath);
668 while ((dp = readdir(dir)) != NULL)
670 if (strcmp(dp->d_name,
".") == 0 || strcmp(dp->d_name,
"..") == 0)
681BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
683 LPSTR lpFileNameA = NULL;
687 lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
690 ret = PathIsDirectoryEmptyA(lpFileNameA);
698BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
700 return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
703BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
708 ret = stat(lpNewFileName, &st);
710 if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
714 SetLastError(ERROR_ALREADY_EXISTS);
720 if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
722 SetLastError(ERROR_ACCESS_DENIED);
727 ret = rename(lpExistingFileName, lpNewFileName);
730 SetLastError(map_posix_err(errno));
735 LPWSTR lpExistingFileNameW = NULL;
736 LPWSTR lpNewFileNameW = NULL;
738 if (!lpExistingFileName || !lpNewFileName)
741 lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName, NULL);
742 if (!lpExistingFileNameW)
744 lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName, NULL);
748 result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, dwFlags);
751 free(lpExistingFileNameW);
752 free(lpNewFileNameW);
757BOOL winpr_DeleteFile(
const char* lpFileName)
763 const int status = unlink(lpFileName);
764 return (status != -1) ? TRUE : FALSE;
766 LPWSTR lpFileNameW = NULL;
770 lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
775 result = DeleteFileW(lpFileNameW);
783BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
786 int ret = rmdir(lpPathName);
789 SetLastError(map_posix_err(errno));
791 SetLastError(STATUS_SUCCESS);
795 LPWSTR lpPathNameW = NULL;
799 lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName, NULL);
804 result = RemoveDirectoryW(lpPathNameW);
812BOOL winpr_PathFileExists(
const char* pszPath)
817 return PathFileExistsA(pszPath);
819 WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath, NULL);
825 result = PathFileExistsW(pathW);
832BOOL winpr_PathMakePath(
const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
837 return PathMakePathA(path, lpAttributes);
839 WCHAR* pathW = ConvertUtf8ToWCharAlloc(path, NULL);
845 result = SHCreateDirectoryExW(NULL, pathW, lpAttributes) == ERROR_SUCCESS;