Coverage Report

Created: 2026-01-17 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/path/shell.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Path Functions
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
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 "../file/file.h"
39
40
#include "../log.h"
41
#define TAG WINPR_TAG("path.shell")
42
43
#if defined(__IOS__)
44
#include "shell_ios.h"
45
#endif
46
47
#if defined(WIN32)
48
#include <windows.h>
49
#include <shlobj.h>
50
#else
51
#include <errno.h>
52
#include <dirent.h>
53
#endif
54
55
static char* GetPath_XDG_CONFIG_HOME(void);
56
static char* GetPath_XDG_RUNTIME_DIR(void);
57
58
/**
59
 * SHGetKnownFolderPath function:
60
 * http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188/
61
 */
62
63
#if defined(WIN32) && !defined(_UWP)
64
65
static char* win_get_known_folder(REFKNOWNFOLDERID id, BOOL currentUser)
66
{
67
  WCHAR* wpath = NULL;
68
  HANDLE handle = currentUser ? NULL : (HANDLE)-1;
69
  if (FAILED(SHGetKnownFolderPath(id, 0, handle, &wpath)))
70
    return NULL;
71
72
  if (!wpath)
73
    return NULL;
74
75
  char* path = ConvertWCharToUtf8Alloc(wpath, NULL);
76
  CoTaskMemFree(wpath);
77
  return path;
78
}
79
#endif
80
81
/**
82
 * XDG Base Directory Specification:
83
 * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
84
 */
85
86
char* GetEnvAlloc(LPCSTR lpName)
87
150k
{
88
150k
  DWORD nSize = 0;
89
150k
  DWORD nStatus = 0;
90
150k
  char* env = NULL;
91
92
150k
  nSize = GetEnvironmentVariableX(lpName, NULL, 0);
93
94
150k
  if (nSize > 0)
95
100k
  {
96
100k
    env = malloc(nSize);
97
98
100k
    if (!env)
99
0
      return NULL;
100
101
100k
    nStatus = GetEnvironmentVariableX(lpName, env, nSize);
102
103
100k
    if (nStatus != (nSize - 1))
104
0
    {
105
0
      free(env);
106
0
      return NULL;
107
0
    }
108
100k
  }
109
110
150k
  return env;
111
150k
}
112
113
static char* GetPath_HOME(void)
114
100k
{
115
100k
  char* path = NULL;
116
#ifdef _WIN32
117
  path = GetEnvAlloc("UserProfile");
118
#elif defined(__IOS__)
119
  path = ios_get_home();
120
#else
121
100k
  path = GetEnvAlloc("HOME");
122
100k
#endif
123
100k
  return path;
124
100k
}
125
126
static char* GetPath_TEMP(void)
127
0
{
128
0
  char* path = NULL;
129
#ifdef _WIN32
130
  path = GetEnvAlloc("TEMP");
131
#elif defined(__IOS__)
132
  path = ios_get_temp();
133
#else
134
0
  path = GetEnvAlloc("TMPDIR");
135
136
0
  if (!path)
137
0
    path = _strdup("/tmp");
138
139
0
#endif
140
0
  return path;
141
0
}
142
143
static char* GetPath_XDG_DATA_HOME(void)
144
0
{
145
0
  char* path = NULL;
146
#if defined(WIN32) || defined(__IOS__)
147
  path = GetPath_XDG_CONFIG_HOME();
148
#else
149
0
  size_t size = 0;
150
0
  char* home = NULL;
151
  /**
152
   * There is a single base directory relative to which user-specific data files should be
153
   * written. This directory is defined by the environment variable $XDG_DATA_HOME.
154
   *
155
   * $XDG_DATA_HOME defines the base directory relative to which user specific data files should
156
   * be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to
157
   * $HOME/.local/share should be used.
158
   */
159
0
  path = GetEnvAlloc("XDG_DATA_HOME");
160
161
0
  if (path)
162
0
    return path;
163
164
0
  home = GetPath_HOME();
165
166
0
  if (!home)
167
0
    return NULL;
168
169
0
  size = strlen(home) + strlen("/.local/share") + 1;
170
0
  path = (char*)malloc(size);
171
172
0
  if (!path)
173
0
  {
174
0
    free(home);
175
0
    return NULL;
176
0
  }
177
178
0
  (void)sprintf_s(path, size, "%s%s", home, "/.local/share");
179
0
  free(home);
180
0
#endif
181
0
  return path;
182
0
}
183
184
static char* GetPath_XDG_CONFIG_HOME(void)
185
50.3k
{
186
50.3k
  char* path = NULL;
187
#if defined(WIN32) && !defined(_UWP)
188
189
  path = win_get_known_folder(&FOLDERID_RoamingAppData, TRUE);
190
191
#elif defined(__IOS__)
192
  path = ios_get_data();
193
#else
194
50.3k
  size_t size = 0;
195
50.3k
  char* home = NULL;
196
  /**
197
   * There is a single base directory relative to which user-specific configuration files should
198
   * be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
199
   *
200
   * $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration
201
   * files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal to
202
   * $HOME/.config should be used.
203
   */
204
50.3k
  path = GetEnvAlloc("XDG_CONFIG_HOME");
205
206
50.3k
  if (path)
207
0
    return path;
208
209
50.3k
  home = GetPath_HOME();
210
211
50.3k
  if (!home)
212
0
    home = GetPath_TEMP();
213
214
50.3k
  if (!home)
215
0
    return NULL;
216
217
50.3k
  size = strlen(home) + strlen("/.config") + 1;
218
50.3k
  path = (char*)malloc(size);
219
220
50.3k
  if (!path)
221
0
  {
222
0
    free(home);
223
0
    return NULL;
224
0
  }
225
226
50.3k
  (void)sprintf_s(path, size, "%s%s", home, "/.config");
227
50.3k
  free(home);
228
50.3k
#endif
229
50.3k
  return path;
230
50.3k
}
231
232
static char* GetPath_SYSTEM_CONFIG_HOME(void)
233
229k
{
234
229k
  char* path = NULL;
235
#if defined(WIN32) && !defined(_UWP)
236
237
  path = win_get_known_folder(&FOLDERID_ProgramData, FALSE);
238
239
#elif defined(__IOS__)
240
  path = ios_get_data();
241
#else
242
229k
  path = _strdup(WINPR_INSTALL_SYSCONFDIR);
243
229k
#endif
244
229k
  return path;
245
229k
}
246
247
static char* GetPath_XDG_CACHE_HOME(void)
248
0
{
249
0
  char* path = NULL;
250
#if defined(WIN32)
251
  {
252
    char* home = GetPath_XDG_RUNTIME_DIR();
253
254
    if (home)
255
    {
256
      path = GetCombinedPath(home, "cache");
257
258
      if (!winpr_PathFileExists(path))
259
        if (!winpr_PathMakePath(path, NULL))
260
          path = NULL;
261
    }
262
263
    free(home);
264
  }
265
#elif defined(__IOS__)
266
  path = ios_get_cache();
267
#else
268
0
  size_t size = 0;
269
  /**
270
   * There is a single base directory relative to which user-specific non-essential (cached) data
271
   * should be written. This directory is defined by the environment variable $XDG_CACHE_HOME.
272
   *
273
   * $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data
274
   * files should be stored. If $XDG_CACHE_HOME is either not set or empty, a default equal to
275
   * $HOME/.cache should be used.
276
   */
277
0
  path = GetEnvAlloc("XDG_CACHE_HOME");
278
279
0
  if (path)
280
0
    return path;
281
282
0
  char* home = GetPath_HOME();
283
284
0
  if (!home)
285
0
    return NULL;
286
287
0
  size = strlen(home) + strlen("/.cache") + 1;
288
0
  path = (char*)malloc(size);
289
290
0
  if (!path)
291
0
  {
292
0
    free(home);
293
0
    return NULL;
294
0
  }
295
296
0
  (void)sprintf_s(path, size, "%s%s", home, "/.cache");
297
0
  free(home);
298
0
#endif
299
0
  return path;
300
0
}
301
302
char* GetPath_XDG_RUNTIME_DIR(void)
303
0
{
304
0
  char* path = NULL;
305
#if defined(WIN32) && !defined(_UWP)
306
307
  path = win_get_known_folder(&FOLDERID_LocalAppData, TRUE);
308
309
#else
310
  /**
311
   * There is a single base directory relative to which user-specific runtime files and other file
312
   * objects should be placed. This directory is defined by the environment variable
313
   * $XDG_RUNTIME_DIR.
314
   *
315
   * $XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential
316
   * runtime files and other file objects (such as sockets, named pipes, ...) should be stored.
317
   * The directory MUST be owned by the user, and he MUST be the only one having read and write
318
   * access to it. Its Unix access mode MUST be 0700.
319
   *
320
   * The lifetime of the directory MUST be bound to the user being logged in. It MUST be created
321
   * when the user first logs in and if the user fully logs out the directory MUST be removed. If
322
   * the user logs in more than once he should get pointed to the same directory, and it is
323
   * mandatory that the directory continues to exist from his first login to his last logout on
324
   * the system, and not removed in between. Files in the directory MUST not survive reboot or a
325
   * full logout/login cycle.
326
   *
327
   * The directory MUST be on a local file system and not shared with any other system. The
328
   * directory MUST by fully-featured by the standards of the operating system. More specifically,
329
   * on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper
330
   * permissions, file locking, sparse files, memory mapping, file change notifications, a
331
   * reliable hard link count must be supported, and no restrictions on the file name character
332
   * set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To
333
   * ensure that your files are not removed, they should have their access time timestamp modified
334
   * at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
335
   *
336
   * If $XDG_RUNTIME_DIR is not set applications should fall back to a replacement directory with
337
   * similar capabilities and print a warning message. Applications should use this directory for
338
   * communication and synchronization purposes and should not place larger files in it, since it
339
   * might reside in runtime memory and cannot necessarily be swapped out to disk.
340
   */
341
0
  path = GetEnvAlloc("XDG_RUNTIME_DIR");
342
0
#endif
343
344
0
  if (path)
345
0
    return path;
346
347
0
  path = GetPath_TEMP();
348
0
  return path;
349
0
}
350
351
char* GetKnownPath(eKnownPathTypes id)
352
329k
{
353
329k
  char* path = NULL;
354
355
329k
  switch (id)
356
329k
  {
357
50.3k
    case KNOWN_PATH_HOME:
358
50.3k
      path = GetPath_HOME();
359
50.3k
      break;
360
361
0
    case KNOWN_PATH_TEMP:
362
0
      path = GetPath_TEMP();
363
0
      break;
364
365
0
    case KNOWN_PATH_XDG_DATA_HOME:
366
0
      path = GetPath_XDG_DATA_HOME();
367
0
      break;
368
369
50.3k
    case KNOWN_PATH_XDG_CONFIG_HOME:
370
50.3k
      path = GetPath_XDG_CONFIG_HOME();
371
50.3k
      break;
372
373
0
    case KNOWN_PATH_XDG_CACHE_HOME:
374
0
      path = GetPath_XDG_CACHE_HOME();
375
0
      break;
376
377
0
    case KNOWN_PATH_XDG_RUNTIME_DIR:
378
0
      path = GetPath_XDG_RUNTIME_DIR();
379
0
      break;
380
381
229k
    case KNOWN_PATH_SYSTEM_CONFIG_HOME:
382
229k
      path = GetPath_SYSTEM_CONFIG_HOME();
383
229k
      break;
384
385
0
    default:
386
0
      path = NULL;
387
0
      break;
388
329k
  }
389
390
329k
  if (!path)
391
0
    WLog_WARN(TAG, "Path %s is NULL", GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(int, id)));
392
329k
  return path;
393
329k
}
394
395
char* GetKnownSubPath(eKnownPathTypes id, const char* path)
396
279k
{
397
279k
  char* knownPath = GetKnownPath(id);
398
279k
  if (!knownPath)
399
0
    return NULL;
400
401
279k
  char* subPath = GetCombinedPath(knownPath, path);
402
279k
  free(knownPath);
403
279k
  return subPath;
404
279k
}
405
406
char* GetEnvironmentPath(char* name)
407
0
{
408
0
  char* env = NULL;
409
0
  DWORD nSize = 0;
410
0
  DWORD nStatus = 0;
411
0
  nSize = GetEnvironmentVariableX(name, NULL, 0);
412
413
0
  if (nSize)
414
0
  {
415
0
    env = (LPSTR)malloc(nSize);
416
417
0
    if (!env)
418
0
      return NULL;
419
420
0
    nStatus = GetEnvironmentVariableX(name, env, nSize);
421
422
0
    if (nStatus != (nSize - 1))
423
0
    {
424
0
      free(env);
425
0
      return NULL;
426
0
    }
427
0
  }
428
429
0
  return env;
430
0
}
431
432
char* GetEnvironmentSubPath(char* name, const char* path)
433
0
{
434
0
  char* env = NULL;
435
0
  char* subpath = NULL;
436
0
  env = GetEnvironmentPath(name);
437
438
0
  if (!env)
439
0
    return NULL;
440
441
0
  subpath = GetCombinedPath(env, path);
442
0
  free(env);
443
0
  return subpath;
444
0
}
445
446
char* GetCombinedPath(const char* basePath, const char* subPath)
447
609k
{
448
609k
  HRESULT status = 0;
449
609k
  char* subPathCpy = NULL;
450
609k
  size_t basePathLength = 0;
451
609k
  size_t subPathLength = 0;
452
453
609k
  if (basePath)
454
609k
    basePathLength = strlen(basePath);
455
456
609k
  if (subPath)
457
609k
    subPathLength = strlen(subPath);
458
459
609k
  const size_t length = basePathLength + subPathLength + 1;
460
609k
  char* path = (char*)calloc(1, length + 1);
461
462
609k
  if (!path)
463
0
    goto fail;
464
465
609k
  if (basePath)
466
609k
    CopyMemory(path, basePath, basePathLength);
467
468
609k
  if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
469
0
    goto fail;
470
471
609k
  if (!subPath)
472
0
    return path;
473
474
609k
  subPathCpy = _strdup(subPath);
475
476
609k
  if (!subPathCpy)
477
0
    goto fail;
478
479
609k
  if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
480
0
    goto fail;
481
482
609k
  status = NativePathCchAppendA(path, length + 1, subPathCpy);
483
609k
  if (FAILED(status))
484
0
    goto fail;
485
486
609k
  free(subPathCpy);
487
609k
  return path;
488
489
0
fail:
490
0
  free(path);
491
0
  free(subPathCpy);
492
0
  return NULL;
493
609k
}
494
495
BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
496
0
{
497
#if defined(_UWP)
498
  return FALSE;
499
#elif defined(_WIN32)
500
  return (SHCreateDirectoryExA(NULL, path, lpAttributes) == ERROR_SUCCESS);
501
#else
502
0
  const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
503
0
  char* dup = NULL;
504
0
  BOOL result = TRUE;
505
  /* we only operate on a non-null, absolute path */
506
#if defined(__OS2__)
507
508
  if (!path)
509
    return FALSE;
510
511
#else
512
513
0
  if (!path || *path != delim)
514
0
    return FALSE;
515
516
0
#endif
517
518
0
  if (!(dup = _strdup(path)))
519
0
    return FALSE;
520
521
#ifdef __OS2__
522
  p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
523
524
  while (p)
525
#else
526
0
  for (char* p = dup; p;)
527
0
#endif
528
0
  {
529
0
    if ((p = strchr(p + 1, delim)))
530
0
      *p = '\0';
531
532
0
    if (mkdir(dup, 0777) != 0)
533
0
      if (errno != EEXIST)
534
0
      {
535
0
        result = FALSE;
536
0
        break;
537
0
      }
538
539
0
    if (p)
540
0
      *p = delim;
541
0
  }
542
543
0
  free(dup);
544
0
  return (result);
545
0
#endif
546
0
}
547
548
BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
549
0
{
550
#if defined(_UWP)
551
  return FALSE;
552
#elif defined(_WIN32)
553
  return (SHCreateDirectoryExW(NULL, path, lpAttributes) == ERROR_SUCCESS);
554
#else
555
0
  const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
556
0
  const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
557
0
  char* dup = NULL;
558
0
  BOOL result = TRUE;
559
  /* we only operate on a non-null, absolute path */
560
#if defined(__OS2__)
561
562
  if (!path)
563
    return FALSE;
564
565
#else
566
567
0
  if (!path || *path != wdelim)
568
0
    return FALSE;
569
570
0
#endif
571
572
0
  dup = ConvertWCharToUtf8Alloc(path, NULL);
573
0
  if (!dup)
574
0
    return FALSE;
575
576
#ifdef __OS2__
577
  p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
578
579
  while (p)
580
#else
581
0
  for (char* p = dup; p;)
582
0
#endif
583
0
  {
584
0
    if ((p = strchr(p + 1, delim)))
585
0
      *p = '\0';
586
587
0
    if (mkdir(dup, 0777) != 0)
588
0
      if (errno != EEXIST)
589
0
      {
590
0
        result = FALSE;
591
0
        break;
592
0
      }
593
594
0
    if (p)
595
0
      *p = delim;
596
0
  }
597
598
0
  free(dup);
599
0
  return (result);
600
0
#endif
601
0
}
602
603
#if !defined(_WIN32) || defined(_UWP)
604
605
BOOL PathIsRelativeA(LPCSTR pszPath)
606
0
{
607
0
  if (!pszPath)
608
0
    return FALSE;
609
610
0
  return pszPath[0] != '/';
611
0
}
612
613
BOOL PathIsRelativeW(LPCWSTR pszPath)
614
0
{
615
0
  LPSTR lpFileNameA = NULL;
616
0
  BOOL ret = FALSE;
617
618
0
  if (!pszPath)
619
0
    goto fail;
620
621
0
  lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
622
0
  if (!lpFileNameA)
623
0
    goto fail;
624
0
  ret = PathIsRelativeA(lpFileNameA);
625
0
fail:
626
0
  free(lpFileNameA);
627
0
  return ret;
628
0
}
629
630
BOOL PathFileExistsA(LPCSTR pszPath)
631
0
{
632
0
  struct stat stat_info;
633
634
0
  if (stat(pszPath, &stat_info) != 0)
635
0
    return FALSE;
636
637
0
  return TRUE;
638
0
}
639
640
BOOL PathFileExistsW(LPCWSTR pszPath)
641
0
{
642
0
  LPSTR lpFileNameA = NULL;
643
0
  BOOL ret = FALSE;
644
645
0
  if (!pszPath)
646
0
    goto fail;
647
0
  lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
648
0
  if (!lpFileNameA)
649
0
    goto fail;
650
651
0
  ret = winpr_PathFileExists(lpFileNameA);
652
0
fail:
653
0
  free(lpFileNameA);
654
0
  return ret;
655
0
}
656
657
BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
658
0
{
659
0
  struct dirent* dp = NULL;
660
0
  int empty = 1;
661
0
  DIR* dir = opendir(pszPath);
662
663
0
  if (dir == NULL) /* Not a directory or doesn't exist */
664
0
    return 1;
665
666
  // NOLINTNEXTLINE(concurrency-mt-unsafe)
667
0
  while ((dp = readdir(dir)) != NULL)
668
0
  {
669
0
    if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
670
0
      continue; /* Skip . and .. */
671
672
0
    empty = 0;
673
0
    break;
674
0
  }
675
676
0
  closedir(dir);
677
0
  return empty;
678
0
}
679
680
BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
681
0
{
682
0
  LPSTR lpFileNameA = NULL;
683
0
  BOOL ret = FALSE;
684
0
  if (!pszPath)
685
0
    goto fail;
686
0
  lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
687
0
  if (!lpFileNameA)
688
0
    goto fail;
689
0
  ret = PathIsDirectoryEmptyA(lpFileNameA);
690
0
fail:
691
0
  free(lpFileNameA);
692
0
  return ret;
693
0
}
694
695
#endif
696
697
BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
698
0
{
699
0
  return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
700
0
}
701
702
BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
703
0
{
704
0
#ifndef _WIN32
705
0
  struct stat st;
706
0
  int ret = 0;
707
0
  ret = stat(lpNewFileName, &st);
708
709
0
  if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
710
0
  {
711
0
    if (ret == 0)
712
0
    {
713
0
      SetLastError(ERROR_ALREADY_EXISTS);
714
0
      return FALSE;
715
0
    }
716
0
  }
717
0
  else
718
0
  {
719
0
    if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
720
0
    {
721
0
      SetLastError(ERROR_ACCESS_DENIED);
722
0
      return FALSE;
723
0
    }
724
0
  }
725
726
0
  ret = rename(lpExistingFileName, lpNewFileName);
727
728
0
  if (ret != 0)
729
0
    SetLastError(map_posix_err(errno));
730
731
0
  return ret == 0;
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
0
}
755
756
BOOL winpr_DeleteFile(const char* lpFileName)
757
0
{
758
0
#ifndef _WIN32
759
0
  if (!lpFileName)
760
0
    return FALSE;
761
762
0
  const int status = unlink(lpFileName);
763
0
  return (status != -1) ? TRUE : FALSE;
764
#else
765
  LPWSTR lpFileNameW = NULL;
766
  BOOL result = FALSE;
767
768
  if (lpFileName)
769
    lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
770
771
  if (!lpFileNameW)
772
    goto cleanup;
773
774
  result = DeleteFileW(lpFileNameW);
775
776
cleanup:
777
  free(lpFileNameW);
778
  return result;
779
#endif
780
0
}
781
782
BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
783
0
{
784
0
#ifndef _WIN32
785
0
  int ret = rmdir(lpPathName);
786
787
0
  if (ret != 0)
788
0
    SetLastError(map_posix_err(errno));
789
0
  else
790
0
    SetLastError(STATUS_SUCCESS);
791
792
0
  return ret == 0;
793
#else
794
  LPWSTR lpPathNameW = NULL;
795
  BOOL result = FALSE;
796
797
  if (lpPathName)
798
    lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName, NULL);
799
800
  if (!lpPathNameW)
801
    goto cleanup;
802
803
  result = RemoveDirectoryW(lpPathNameW);
804
805
cleanup:
806
  free(lpPathNameW);
807
  return result;
808
#endif
809
0
}
810
811
BOOL winpr_PathFileExists(const char* pszPath)
812
0
{
813
0
  if (!pszPath)
814
0
    return FALSE;
815
0
#ifndef _WIN32
816
0
  return PathFileExistsA(pszPath);
817
#else
818
  WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath, NULL);
819
  BOOL result = FALSE;
820
821
  if (!pathW)
822
    return FALSE;
823
824
  result = PathFileExistsW(pathW);
825
  free(pathW);
826
827
  return result;
828
#endif
829
0
}
830
831
BOOL winpr_PathMakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
832
0
{
833
0
  if (!path)
834
0
    return FALSE;
835
0
#ifndef _WIN32
836
0
  return PathMakePathA(path, lpAttributes);
837
#else
838
  WCHAR* pathW = ConvertUtf8ToWCharAlloc(path, NULL);
839
  BOOL result = FALSE;
840
841
  if (!pathW)
842
    return FALSE;
843
844
  result = SHCreateDirectoryExW(NULL, pathW, lpAttributes) == ERROR_SUCCESS;
845
  free(pathW);
846
847
  return result;
848
#endif
849
0
}