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