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