Coverage Report

Created: 2026-02-26 06:50

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
0
{
88
0
  DWORD nSize = 0;
89
0
  DWORD nStatus = 0;
90
0
  char* env = NULL;
91
92
0
  nSize = GetEnvironmentVariableX(lpName, NULL, 0);
93
94
0
  if (nSize > 0)
95
0
  {
96
0
    env = malloc(nSize);
97
98
0
    if (!env)
99
0
      return NULL;
100
101
0
    nStatus = GetEnvironmentVariableX(lpName, env, nSize);
102
103
0
    if (nStatus != (nSize - 1))
104
0
    {
105
0
      free(env);
106
0
      return NULL;
107
0
    }
108
0
  }
109
110
0
  return env;
111
0
}
112
113
static char* GetPath_HOME(void)
114
0
{
115
0
  char* path = NULL;
116
#ifdef _WIN32
117
  path = GetEnvAlloc("UserProfile");
118
#elif defined(__IOS__)
119
  path = ios_get_home();
120
#else
121
0
  path = GetEnvAlloc("HOME");
122
0
#endif
123
0
  return path;
124
0
}
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
0
{
186
0
  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
0
  size_t size = 0;
195
0
  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
0
  path = GetEnvAlloc("XDG_CONFIG_HOME");
205
206
0
  if (path)
207
0
    return path;
208
209
0
  home = GetPath_HOME();
210
211
0
  if (!home)
212
0
    home = GetPath_TEMP();
213
214
0
  if (!home)
215
0
    return NULL;
216
217
0
  size = strlen(home) + strlen("/.config") + 1;
218
0
  path = (char*)malloc(size);
219
220
0
  if (!path)
221
0
  {
222
0
    free(home);
223
0
    return NULL;
224
0
  }
225
226
0
  (void)sprintf_s(path, size, "%s%s", home, "/.config");
227
0
  free(home);
228
0
#endif
229
0
  return path;
230
0
}
231
232
static char* GetPath_SYSTEM_CONFIG_HOME(void)
233
0
{
234
0
  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
0
  path = _strdup(WINPR_INSTALL_SYSCONFDIR);
243
0
#endif
244
0
  return path;
245
0
}
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
0
{
353
0
  char* path = NULL;
354
355
0
  switch (id)
356
0
  {
357
0
    case KNOWN_PATH_HOME:
358
0
      path = GetPath_HOME();
359
0
      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
0
    case KNOWN_PATH_XDG_CONFIG_HOME:
370
0
      path = GetPath_XDG_CONFIG_HOME();
371
0
      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
0
    case KNOWN_PATH_SYSTEM_CONFIG_HOME:
382
0
      path = GetPath_SYSTEM_CONFIG_HOME();
383
0
      break;
384
385
0
    default:
386
0
      path = NULL;
387
0
      break;
388
0
  }
389
390
0
  if (!path)
391
0
    WLog_WARN(TAG, "Path %s is NULL", GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(int, id)));
392
0
  return path;
393
0
}
394
395
char* GetKnownSubPath(eKnownPathTypes id, const char* path)
396
0
{
397
0
  if (!path)
398
0
    return GetKnownSubPathV(id, "%s", "");
399
0
  return GetKnownSubPathV(id, "%s", path);
400
0
}
401
402
char* GetKnownSubPathV(eKnownPathTypes id, const char* path, ...)
403
0
{
404
0
  va_list ap = WINPR_C_ARRAY_INIT;
405
406
0
  va_start(ap, path);
407
0
  char* str = GetKnownSubPathVA(id, path, ap);
408
0
  va_end(ap);
409
0
  return str;
410
0
}
411
412
char* GetKnownSubPathVA(eKnownPathTypes id, const char* path, va_list ap)
413
0
{
414
0
  char* knownPath = GetKnownPath(id);
415
0
  if (!knownPath)
416
0
    return NULL;
417
418
0
  char* subPath = GetCombinedPathVA(knownPath, path, ap);
419
0
  free(knownPath);
420
0
  return subPath;
421
0
}
422
423
char* GetEnvironmentPath(char* name)
424
0
{
425
0
  char* env = NULL;
426
0
  DWORD nSize = 0;
427
0
  DWORD nStatus = 0;
428
0
  nSize = GetEnvironmentVariableX(name, NULL, 0);
429
430
0
  if (nSize)
431
0
  {
432
0
    env = (LPSTR)malloc(nSize);
433
434
0
    if (!env)
435
0
      return NULL;
436
437
0
    nStatus = GetEnvironmentVariableX(name, env, nSize);
438
439
0
    if (nStatus != (nSize - 1))
440
0
    {
441
0
      free(env);
442
0
      return NULL;
443
0
    }
444
0
  }
445
446
0
  return env;
447
0
}
448
449
char* GetEnvironmentSubPath(char* name, const char* path)
450
0
{
451
0
  if (!path)
452
0
    return GetEnvironmentSubPathV(name, "%s", "");
453
0
  return GetEnvironmentSubPathV(name, "%s", path);
454
0
}
455
456
char* GetEnvironmentSubPathV(char* name, const char* path, ...)
457
0
{
458
0
  va_list ap = WINPR_C_ARRAY_INIT;
459
0
  va_start(ap, path);
460
0
  char* str = GetEnvironmentSubPathVA(name, path, ap);
461
0
  va_end(ap);
462
0
  return str;
463
0
}
464
465
char* GetEnvironmentSubPathVA(char* name, WINPR_FORMAT_ARG const char* path, va_list ap)
466
0
{
467
0
  char* env = GetEnvironmentPath(name);
468
469
0
  if (!env)
470
0
    return NULL;
471
472
0
  char* subpath = GetCombinedPathVA(env, path, ap);
473
0
  free(env);
474
0
  return subpath;
475
0
}
476
477
char* GetCombinedPath(const char* basePath, const char* subPathFmt)
478
0
{
479
0
  if (!subPathFmt)
480
0
    return GetCombinedPathV(basePath, "%s", "");
481
0
  return GetCombinedPathV(basePath, "%s", subPathFmt);
482
0
}
483
484
char* GetCombinedPathV(const char* basePath, const char* subPathFmt, ...)
485
0
{
486
0
  va_list ap = WINPR_C_ARRAY_INIT;
487
488
0
  va_start(ap, subPathFmt);
489
0
  char* str = GetCombinedPathVA(basePath, subPathFmt, ap);
490
0
  va_end(ap);
491
0
  return str;
492
0
}
493
494
char* GetCombinedPathVA(const char* basePath, WINPR_FORMAT_ARG const char* subPathFmt, va_list ap)
495
0
{
496
0
  HRESULT status = 0;
497
0
  char* subPathCpy = NULL;
498
0
  size_t basePathLength = 0;
499
0
  size_t subPathLength = 0;
500
501
0
  if (basePath)
502
0
    basePathLength = strlen(basePath);
503
504
0
  bool haveSubPath = subPathFmt && (*subPathFmt != '\0');
505
0
  if (haveSubPath)
506
0
  {
507
0
    const int rc = winpr_vasprintf(&subPathCpy, &subPathLength, subPathFmt, ap);
508
0
    if (rc < 0)
509
0
      return NULL;
510
0
    if (rc == 0)
511
0
    {
512
0
      free(subPathCpy);
513
0
      subPathCpy = NULL;
514
0
      subPathLength = 0;
515
0
      haveSubPath = false;
516
0
    }
517
0
  }
518
519
0
  const size_t length = basePathLength + subPathLength + 1;
520
0
  char* path = (char*)calloc(1, length + 1);
521
522
0
  if (!path)
523
0
    goto fail;
524
525
0
  if (basePath)
526
0
    CopyMemory(path, basePath, basePathLength);
527
528
0
  if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
529
0
    goto fail;
530
531
0
  if (!haveSubPath)
532
0
    return path;
533
534
0
  if (!subPathCpy)
535
0
    goto fail;
536
537
0
  if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
538
0
    goto fail;
539
540
0
  status = NativePathCchAppendA(path, length + 1, subPathCpy);
541
0
  if (FAILED(status))
542
0
    goto fail;
543
544
0
  free(subPathCpy);
545
0
  return path;
546
547
0
fail:
548
0
  free(path);
549
0
  free(subPathCpy);
550
0
  return NULL;
551
0
}
552
553
BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
554
0
{
555
#if defined(_UWP)
556
  return FALSE;
557
#elif defined(_WIN32)
558
  return (SHCreateDirectoryExA(NULL, path, lpAttributes) == ERROR_SUCCESS);
559
#else
560
0
  const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
561
0
  char* dup = NULL;
562
0
  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
0
  if (!path || *path != delim)
572
0
    return FALSE;
573
574
0
#endif
575
576
0
  if (!(dup = _strdup(path)))
577
0
    return FALSE;
578
579
#ifdef __OS2__
580
  p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
581
582
  while (p)
583
#else
584
0
  for (char* p = dup; p;)
585
0
#endif
586
0
  {
587
0
    if ((p = strchr(p + 1, delim)))
588
0
      *p = '\0';
589
590
0
    if (mkdir(dup, 0777) != 0)
591
0
      if (errno != EEXIST)
592
0
      {
593
0
        result = FALSE;
594
0
        break;
595
0
      }
596
597
0
    if (p)
598
0
      *p = delim;
599
0
  }
600
601
0
  free(dup);
602
0
  return (result);
603
0
#endif
604
0
}
605
606
BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
607
0
{
608
#if defined(_UWP)
609
  return FALSE;
610
#elif defined(_WIN32)
611
  return (SHCreateDirectoryExW(NULL, path, lpAttributes) == ERROR_SUCCESS);
612
#else
613
0
  const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
614
0
  const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
615
0
  char* dup = NULL;
616
0
  BOOL result = TRUE;
617
  /* we only operate on a non-null, absolute path */
618
#if defined(__OS2__)
619
620
  if (!path)
621
    return FALSE;
622
623
#else
624
625
0
  if (!path || *path != wdelim)
626
0
    return FALSE;
627
628
0
#endif
629
630
0
  dup = ConvertWCharToUtf8Alloc(path, NULL);
631
0
  if (!dup)
632
0
    return FALSE;
633
634
#ifdef __OS2__
635
  p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
636
637
  while (p)
638
#else
639
0
  for (char* p = dup; p;)
640
0
#endif
641
0
  {
642
0
    if ((p = strchr(p + 1, delim)))
643
0
      *p = '\0';
644
645
0
    if (mkdir(dup, 0777) != 0)
646
0
      if (errno != EEXIST)
647
0
      {
648
0
        result = FALSE;
649
0
        break;
650
0
      }
651
652
0
    if (p)
653
0
      *p = delim;
654
0
  }
655
656
0
  free(dup);
657
0
  return (result);
658
0
#endif
659
0
}
660
661
#if !defined(_WIN32) || defined(_UWP)
662
663
BOOL PathIsRelativeA(LPCSTR pszPath)
664
0
{
665
0
  if (!pszPath)
666
0
    return FALSE;
667
668
0
  return pszPath[0] != '/';
669
0
}
670
671
BOOL PathIsRelativeW(LPCWSTR pszPath)
672
0
{
673
0
  LPSTR lpFileNameA = NULL;
674
0
  BOOL ret = FALSE;
675
676
0
  if (!pszPath)
677
0
    goto fail;
678
679
0
  lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
680
0
  if (!lpFileNameA)
681
0
    goto fail;
682
0
  ret = PathIsRelativeA(lpFileNameA);
683
0
fail:
684
0
  free(lpFileNameA);
685
0
  return ret;
686
0
}
687
688
BOOL PathFileExistsA(LPCSTR pszPath)
689
0
{
690
0
  struct stat stat_info;
691
692
0
  if (stat(pszPath, &stat_info) != 0)
693
0
    return FALSE;
694
695
0
  return TRUE;
696
0
}
697
698
BOOL PathFileExistsW(LPCWSTR pszPath)
699
0
{
700
0
  LPSTR lpFileNameA = NULL;
701
0
  BOOL ret = FALSE;
702
703
0
  if (!pszPath)
704
0
    goto fail;
705
0
  lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
706
0
  if (!lpFileNameA)
707
0
    goto fail;
708
709
0
  ret = winpr_PathFileExists(lpFileNameA);
710
0
fail:
711
0
  free(lpFileNameA);
712
0
  return ret;
713
0
}
714
715
BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
716
0
{
717
0
  struct dirent* dp = NULL;
718
0
  int empty = 1;
719
0
  DIR* dir = opendir(pszPath);
720
721
0
  if (dir == NULL) /* Not a directory or doesn't exist */
722
0
    return 1;
723
724
  // NOLINTNEXTLINE(concurrency-mt-unsafe)
725
0
  while ((dp = readdir(dir)) != NULL)
726
0
  {
727
0
    if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
728
0
      continue; /* Skip . and .. */
729
730
0
    empty = 0;
731
0
    break;
732
0
  }
733
734
0
  closedir(dir);
735
0
  return empty;
736
0
}
737
738
BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
739
0
{
740
0
  LPSTR lpFileNameA = NULL;
741
0
  BOOL ret = FALSE;
742
0
  if (!pszPath)
743
0
    goto fail;
744
0
  lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, NULL);
745
0
  if (!lpFileNameA)
746
0
    goto fail;
747
0
  ret = PathIsDirectoryEmptyA(lpFileNameA);
748
0
fail:
749
0
  free(lpFileNameA);
750
0
  return ret;
751
0
}
752
753
#endif
754
755
BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
756
0
{
757
0
  return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
758
0
}
759
760
BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
761
0
{
762
0
#ifndef _WIN32
763
0
  struct stat st;
764
0
  int ret = 0;
765
0
  ret = stat(lpNewFileName, &st);
766
767
0
  if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
768
0
  {
769
0
    if (ret == 0)
770
0
    {
771
0
      SetLastError(ERROR_ALREADY_EXISTS);
772
0
      return FALSE;
773
0
    }
774
0
  }
775
0
  else
776
0
  {
777
0
    if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
778
0
    {
779
0
      SetLastError(ERROR_ACCESS_DENIED);
780
0
      return FALSE;
781
0
    }
782
0
  }
783
784
0
  ret = rename(lpExistingFileName, lpNewFileName);
785
786
0
  if (ret != 0)
787
0
    SetLastError(map_posix_err(errno));
788
789
0
  return ret == 0;
790
#else
791
  BOOL result = FALSE;
792
  LPWSTR lpExistingFileNameW = NULL;
793
  LPWSTR lpNewFileNameW = NULL;
794
795
  if (!lpExistingFileName || !lpNewFileName)
796
    return FALSE;
797
798
  lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName, NULL);
799
  if (!lpExistingFileNameW)
800
    goto cleanup;
801
  lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName, NULL);
802
  if (!lpNewFileNameW)
803
    goto cleanup;
804
805
  result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, dwFlags);
806
807
cleanup:
808
  free(lpExistingFileNameW);
809
  free(lpNewFileNameW);
810
  return result;
811
#endif
812
0
}
813
814
BOOL winpr_DeleteFile(const char* lpFileName)
815
0
{
816
0
#ifndef _WIN32
817
0
  if (!lpFileName)
818
0
    return FALSE;
819
820
0
  const int status = unlink(lpFileName);
821
0
  return (status != -1) ? TRUE : FALSE;
822
#else
823
  LPWSTR lpFileNameW = NULL;
824
  BOOL result = FALSE;
825
826
  if (lpFileName)
827
    lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, NULL);
828
829
  if (!lpFileNameW)
830
    goto cleanup;
831
832
  result = DeleteFileW(lpFileNameW);
833
834
cleanup:
835
  free(lpFileNameW);
836
  return result;
837
#endif
838
0
}
839
840
BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
841
0
{
842
0
#ifndef _WIN32
843
0
  int ret = rmdir(lpPathName);
844
845
0
  if (ret != 0)
846
0
    SetLastError(map_posix_err(errno));
847
0
  else
848
0
    SetLastError(STATUS_SUCCESS);
849
850
0
  return ret == 0;
851
#else
852
  LPWSTR lpPathNameW = NULL;
853
  BOOL result = FALSE;
854
855
  if (lpPathName)
856
    lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName, NULL);
857
858
  if (!lpPathNameW)
859
    goto cleanup;
860
861
  result = RemoveDirectoryW(lpPathNameW);
862
863
cleanup:
864
  free(lpPathNameW);
865
  return result;
866
#endif
867
0
}
868
869
BOOL winpr_PathFileExists(const char* pszPath)
870
0
{
871
0
  if (!pszPath)
872
0
    return FALSE;
873
0
#ifndef _WIN32
874
0
  return PathFileExistsA(pszPath);
875
#else
876
  WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath, NULL);
877
  BOOL result = FALSE;
878
879
  if (!pathW)
880
    return FALSE;
881
882
  result = PathFileExistsW(pathW);
883
  free(pathW);
884
885
  return result;
886
#endif
887
0
}
888
889
BOOL winpr_PathMakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
890
0
{
891
0
  if (!path)
892
0
    return FALSE;
893
0
#ifndef _WIN32
894
0
  return PathMakePathA(path, lpAttributes);
895
#else
896
  WCHAR* pathW = ConvertUtf8ToWCharAlloc(path, NULL);
897
  BOOL result = FALSE;
898
899
  if (!pathW)
900
    return FALSE;
901
902
  result = SHCreateDirectoryExW(NULL, pathW, lpAttributes) == ERROR_SUCCESS;
903
  free(pathW);
904
905
  return result;
906
#endif
907
0
}