Coverage Report

Created: 2025-08-29 06:48

/src/fwupd/libfwupdplugin/fu-path.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2017 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuCommon"
8
9
#include "config.h"
10
11
#include <errno.h>
12
#include <glib/gstdio.h>
13
14
#ifdef _WIN32
15
#include <stdlib.h>
16
#endif
17
18
#include "fwupd-error.h"
19
20
#include "fu-common.h"
21
#include "fu-path.h"
22
23
/**
24
 * fu_path_rmtree:
25
 * @directory: a directory name
26
 * @error: (nullable): optional return location for an error
27
 *
28
 * Recursively removes a directory.
29
 *
30
 * Returns: %TRUE for success, %FALSE otherwise
31
 *
32
 * Since: 1.8.2
33
 **/
34
gboolean
35
fu_path_rmtree(const gchar *directory, GError **error)
36
0
{
37
0
  const gchar *filename;
38
0
  g_autoptr(GDir) dir = NULL;
39
40
0
  g_return_val_if_fail(directory != NULL, FALSE);
41
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
42
43
  /* try to open */
44
0
  g_debug("removing %s", directory);
45
0
  dir = g_dir_open(directory, 0, error);
46
0
  if (dir == NULL)
47
0
    return FALSE;
48
49
  /* find each */
50
0
  while ((filename = g_dir_read_name(dir))) {
51
0
    g_autofree gchar *src = NULL;
52
0
    src = g_build_filename(directory, filename, NULL);
53
0
    if (g_file_test(src, G_FILE_TEST_IS_DIR)) {
54
0
      if (!fu_path_rmtree(src, error))
55
0
        return FALSE;
56
0
    } else {
57
0
      if (g_unlink(src) != 0) {
58
0
        g_set_error(error,
59
0
              FWUPD_ERROR,
60
0
              FWUPD_ERROR_INTERNAL,
61
0
              "Failed to delete: %s",
62
0
              src);
63
0
        return FALSE;
64
0
      }
65
0
    }
66
0
  }
67
0
  if (g_remove(directory) != 0) {
68
0
    g_set_error(error,
69
0
          FWUPD_ERROR,
70
0
          FWUPD_ERROR_INTERNAL,
71
0
          "Failed to delete: %s",
72
0
          directory);
73
0
    return FALSE;
74
0
  }
75
0
  return TRUE;
76
0
}
77
78
static gboolean
79
fu_path_get_file_list_internal(GPtrArray *files, const gchar *directory, GError **error)
80
0
{
81
0
  const gchar *filename;
82
0
  g_autoptr(GDir) dir = NULL;
83
84
  /* try to open */
85
0
  dir = g_dir_open(directory, 0, error);
86
0
  if (dir == NULL)
87
0
    return FALSE;
88
89
  /* find each */
90
0
  while ((filename = g_dir_read_name(dir))) {
91
0
    g_autofree gchar *src = g_build_filename(directory, filename, NULL);
92
0
    if (g_file_test(src, G_FILE_TEST_IS_SYMLINK))
93
0
      continue;
94
0
    if (g_file_test(src, G_FILE_TEST_IS_DIR)) {
95
0
      if (!fu_path_get_file_list_internal(files, src, error))
96
0
        return FALSE;
97
0
    } else {
98
0
      g_ptr_array_add(files, g_steal_pointer(&src));
99
0
    }
100
0
  }
101
0
  return TRUE;
102
0
}
103
104
/**
105
 * fu_path_get_files:
106
 * @path: a directory name
107
 * @error: (nullable): optional return location for an error
108
 *
109
 * Returns every file found under @directory, and any subdirectory.
110
 * If any path under @directory cannot be accessed due to permissions an error
111
 * will be returned.
112
 *
113
 * Returns: (transfer container) (element-type utf8): array of files, or %NULL for error
114
 *
115
 * Since: 1.8.2
116
 **/
117
GPtrArray *
118
fu_path_get_files(const gchar *path, GError **error)
119
0
{
120
0
  g_autoptr(GPtrArray) files = g_ptr_array_new_with_free_func(g_free);
121
122
0
  g_return_val_if_fail(path != NULL, NULL);
123
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
124
125
0
  if (!fu_path_get_file_list_internal(files, path, error))
126
0
    return NULL;
127
0
  return g_steal_pointer(&files);
128
0
}
129
130
/**
131
 * fu_path_mkdir:
132
 * @dirname: a directory name
133
 * @error: (nullable): optional return location for an error
134
 *
135
 * Creates any required directories, including any parent directories.
136
 *
137
 * Returns: %TRUE for success
138
 *
139
 * Since: 1.8.2
140
 **/
141
gboolean
142
fu_path_mkdir(const gchar *dirname, GError **error)
143
0
{
144
0
  g_return_val_if_fail(dirname != NULL, FALSE);
145
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
146
147
0
  if (!g_file_test(dirname, G_FILE_TEST_IS_DIR))
148
0
    g_debug("creating path %s", dirname);
149
0
  if (g_mkdir_with_parents(dirname, 0755) == -1) {
150
0
    g_set_error(error,
151
0
          FWUPD_ERROR,
152
0
          FWUPD_ERROR_INTERNAL,
153
0
          "Failed to create '%s': %s",
154
0
          dirname,
155
0
          fwupd_strerror(errno));
156
0
    return FALSE;
157
0
  }
158
0
  return TRUE;
159
0
}
160
161
/**
162
 * fu_path_mkdir_parent:
163
 * @filename: a full pathname
164
 * @error: (nullable): optional return location for an error
165
 *
166
 * Creates any required directories, including any parent directories.
167
 *
168
 * Returns: %TRUE for success
169
 *
170
 * Since: 1.8.2
171
 **/
172
gboolean
173
fu_path_mkdir_parent(const gchar *filename, GError **error)
174
0
{
175
0
  g_autofree gchar *parent = NULL;
176
177
0
  g_return_val_if_fail(filename != NULL, FALSE);
178
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
179
180
0
  parent = g_path_get_dirname(filename);
181
0
  return fu_path_mkdir(parent, error);
182
0
}
183
184
/**
185
 * fu_path_find_program:
186
 * @basename: the program to search
187
 * @error: (nullable): optional return location for an error
188
 *
189
 * Looks for a program in the PATH variable
190
 *
191
 * Returns: a new #gchar, or %NULL for error
192
 *
193
 * Since: 1.8.2
194
 **/
195
gchar *
196
fu_path_find_program(const gchar *basename, GError **error)
197
0
{
198
0
  gchar *fn = g_find_program_in_path(basename);
199
0
  if (fn == NULL) {
200
0
    g_set_error(error,
201
0
          FWUPD_ERROR,
202
0
          FWUPD_ERROR_NOT_SUPPORTED,
203
0
          "missing executable %s in PATH",
204
0
          basename);
205
0
    return NULL;
206
0
  }
207
0
  return fn;
208
0
}
209
210
/**
211
 * fu_path_get_win32_basedir:
212
 *
213
 * Gets the base directory that fwupd has been launched from on Windows.
214
 * This is the directory containing all subdirectories (IE 'C:\Program Files (x86)\fwupd\')
215
 *
216
 * Returns: The system path, or %NULL if invalid
217
 *
218
 * Since: 1.8.2
219
 **/
220
static gchar *
221
fu_path_get_win32_basedir(void)
222
0
{
223
#ifdef _WIN32
224
  char drive_buf[_MAX_DRIVE];
225
  char dir_buf[_MAX_DIR];
226
  _splitpath(_pgmptr, drive_buf, dir_buf, NULL, NULL);
227
  return g_build_filename(drive_buf, dir_buf, "..", NULL);
228
#endif
229
0
  return NULL;
230
0
}
231
232
/**
233
 * fu_path_from_kind:
234
 * @path_kind: a #FuPathKind e.g. %FU_PATH_KIND_DATADIR_PKG
235
 *
236
 * Gets a fwupd-specific system path. These can be overridden with various
237
 * environment variables, for instance %FWUPD_DATADIR.
238
 *
239
 * Returns: a system path, or %NULL if invalid
240
 *
241
 * Since: 1.8.2
242
 **/
243
gchar *
244
fu_path_from_kind(FuPathKind path_kind)
245
0
{
246
0
  const gchar *tmp;
247
0
  g_autofree gchar *basedir = NULL;
248
249
0
  switch (path_kind) {
250
  /* /var */
251
0
  case FU_PATH_KIND_LOCALSTATEDIR:
252
0
    tmp = g_getenv("FWUPD_LOCALSTATEDIR");
253
0
    if (tmp != NULL)
254
0
      return g_strdup(tmp);
255
#ifdef _WIN32
256
    return g_build_filename(g_getenv("USERPROFILE"),
257
          PACKAGE_NAME,
258
          FWUPD_LOCALSTATEDIR,
259
          NULL);
260
#else
261
0
    tmp = g_getenv("SNAP_COMMON");
262
0
    if (tmp != NULL)
263
0
      return g_build_filename(tmp, FWUPD_LOCALSTATEDIR, NULL);
264
0
    return g_build_filename(FWUPD_LOCALSTATEDIR, NULL);
265
0
#endif
266
  /* /proc */
267
0
  case FU_PATH_KIND_PROCFS:
268
0
    tmp = g_getenv("FWUPD_PROCFS");
269
0
    if (tmp != NULL)
270
0
      return g_strdup(tmp);
271
0
    return g_strdup("/proc");
272
  /* /sys */
273
0
  case FU_PATH_KIND_SYSFSDIR:
274
0
    tmp = g_getenv("FWUPD_SYSFSDIR");
275
0
    if (tmp != NULL)
276
0
      return g_strdup(tmp);
277
0
    return g_strdup("/sys");
278
  /* /sys/firmware */
279
0
  case FU_PATH_KIND_SYSFSDIR_FW:
280
0
    tmp = g_getenv("FWUPD_SYSFSFWDIR");
281
0
    if (tmp != NULL)
282
0
      return g_strdup(tmp);
283
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
284
0
    return g_build_filename(basedir, "firmware", NULL);
285
  /* /sys/class/tpm */
286
0
  case FU_PATH_KIND_SYSFSDIR_TPM:
287
0
    tmp = g_getenv("FWUPD_SYSFSTPMDIR");
288
0
    if (tmp != NULL)
289
0
      return g_strdup(tmp);
290
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
291
0
    return g_build_filename(basedir, "class", "tpm", NULL);
292
  /* /sys/bus/platform/drivers */
293
0
  case FU_PATH_KIND_SYSFSDIR_DRIVERS:
294
0
    tmp = g_getenv("FWUPD_SYSFSDRIVERDIR");
295
0
    if (tmp != NULL)
296
0
      return g_strdup(tmp);
297
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
298
0
    return g_build_filename(basedir, "bus", "platform", "drivers", NULL);
299
  /* /sys/kernel/security */
300
0
  case FU_PATH_KIND_SYSFSDIR_SECURITY:
301
0
    tmp = g_getenv("FWUPD_SYSFSSECURITYDIR");
302
0
    if (tmp != NULL)
303
0
      return g_strdup(tmp);
304
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
305
0
    return g_build_filename(basedir, "kernel", "security", NULL);
306
  /* /sys/class/dmi/id */
307
0
  case FU_PATH_KIND_SYSFSDIR_DMI:
308
0
    tmp = g_getenv("FWUPD_SYSFSDMIDIR");
309
0
    if (tmp != NULL)
310
0
      return g_strdup(tmp);
311
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
312
0
    return g_build_filename(basedir, "class", "dmi", "id", NULL);
313
  /* /sys/firmware/acpi/tables */
314
0
  case FU_PATH_KIND_ACPI_TABLES:
315
0
    tmp = g_getenv("FWUPD_ACPITABLESDIR");
316
0
    if (tmp != NULL)
317
0
      return g_strdup(tmp);
318
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
319
0
    return g_build_filename(basedir, "firmware", "acpi", "tables", NULL);
320
  /* /sys/module/firmware_class/parameters/path */
321
0
  case FU_PATH_KIND_FIRMWARE_SEARCH:
322
0
    tmp = g_getenv("FWUPD_FIRMWARESEARCH");
323
0
    if (tmp != NULL)
324
0
      return g_strdup(tmp);
325
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
326
0
    return g_build_filename(basedir,
327
0
          "module",
328
0
          "firmware_class",
329
0
          "parameters",
330
0
          "path",
331
0
          NULL);
332
  /* /etc */
333
0
  case FU_PATH_KIND_SYSCONFDIR:
334
0
    tmp = g_getenv("FWUPD_SYSCONFDIR");
335
0
    if (tmp != NULL)
336
0
      return g_strdup(tmp);
337
0
    tmp = g_getenv("SNAP");
338
0
    if (tmp != NULL)
339
0
      return g_build_filename(tmp, FWUPD_SYSCONFDIR, NULL);
340
0
    basedir = fu_path_get_win32_basedir();
341
0
    if (basedir != NULL)
342
0
      return g_build_filename(basedir, FWUPD_SYSCONFDIR, NULL);
343
0
    return g_strdup(FWUPD_SYSCONFDIR);
344
  /* /usr/libexec/ */
345
0
  case FU_PATH_KIND_LIBEXECDIR:
346
0
    tmp = g_getenv("FWUPD_LIBEXECDIR");
347
0
    if (tmp != NULL)
348
0
      return g_strdup(tmp);
349
0
    tmp = g_getenv("SNAP");
350
0
    if (tmp != NULL)
351
0
      return g_build_filename(tmp, FWUPD_LIBEXECDIR, NULL);
352
0
    return g_strdup(FWUPD_LIBEXECDIR);
353
  /* /usr/lib/<triplet>/fwupd-#VERSION# */
354
0
  case FU_PATH_KIND_LIBDIR_PKG:
355
0
    tmp = g_getenv("FWUPD_LIBDIR_PKG");
356
0
    if (tmp != NULL)
357
0
      return g_strdup(tmp);
358
0
    tmp = g_getenv("SNAP");
359
0
    if (tmp != NULL)
360
0
      return g_build_filename(tmp, FWUPD_LIBDIR_PKG, NULL);
361
0
    basedir = fu_path_get_win32_basedir();
362
0
    if (basedir != NULL)
363
0
      return g_build_filename(basedir, FWUPD_LIBDIR_PKG, NULL);
364
0
    return g_build_filename(FWUPD_LIBDIR_PKG, NULL);
365
  /* /usr/share/fwupd */
366
0
  case FU_PATH_KIND_DATADIR_PKG:
367
0
    tmp = g_getenv("FWUPD_DATADIR");
368
0
    if (tmp != NULL)
369
0
      return g_strdup(tmp);
370
0
    tmp = g_getenv("SNAP");
371
0
    if (tmp != NULL)
372
0
      return g_build_filename(tmp, FWUPD_DATADIR, PACKAGE_NAME, NULL);
373
0
    basedir = fu_path_get_win32_basedir();
374
0
    if (basedir != NULL)
375
0
      return g_build_filename(basedir, FWUPD_DATADIR, PACKAGE_NAME, NULL);
376
0
    return g_build_filename(FWUPD_DATADIR, PACKAGE_NAME, NULL);
377
  /* /usr/libexec/fwupd */
378
0
  case FU_PATH_KIND_LIBEXECDIR_PKG:
379
0
    tmp = g_getenv("FWUPD_LIBEXECDIR_PKG");
380
0
    if (tmp != NULL)
381
0
      return g_strdup(tmp);
382
0
    tmp = g_getenv("SNAP");
383
0
    if (tmp != NULL)
384
0
      return g_build_filename(tmp, FWUPD_LIBEXECDIR, PACKAGE_NAME, NULL);
385
0
    return g_build_filename(FWUPD_LIBEXECDIR, PACKAGE_NAME, NULL);
386
  /* /usr/share/hwdata */
387
0
  case FU_PATH_KIND_DATADIR_VENDOR_IDS:
388
0
    tmp = g_getenv("FWUPD_DATADIR_VENDOR_IDS");
389
0
    if (tmp != NULL)
390
0
      return g_strdup(tmp);
391
0
    tmp = g_getenv("SNAP");
392
0
    if (tmp != NULL)
393
0
      return g_build_filename(tmp, FWUPD_DATADIR_VENDOR_IDS, NULL);
394
0
    return g_strdup(FWUPD_DATADIR_VENDOR_IDS);
395
  /* /usr/share/fwupd/quirks.d */
396
0
  case FU_PATH_KIND_DATADIR_QUIRKS:
397
0
    tmp = g_getenv("FWUPD_DATADIR_QUIRKS");
398
0
    if (tmp != NULL)
399
0
      return g_strdup(tmp);
400
0
    basedir = fu_path_from_kind(FU_PATH_KIND_DATADIR_PKG);
401
0
    return g_build_filename(basedir, "quirks.d", NULL);
402
  /* /usr/libexec/fwupd/efi */
403
0
  case FU_PATH_KIND_EFIAPPDIR:
404
0
    tmp = g_getenv("FWUPD_EFIAPPDIR");
405
0
    if (tmp != NULL)
406
0
      return g_strdup(tmp);
407
#ifdef EFI_APP_LOCATION
408
    tmp = g_getenv("SNAP");
409
    if (tmp != NULL)
410
      return g_build_filename(tmp, EFI_APP_LOCATION, NULL);
411
    return g_strdup(EFI_APP_LOCATION);
412
#else
413
0
    return NULL;
414
0
#endif
415
  /* /etc/fwupd */
416
0
  case FU_PATH_KIND_SYSCONFDIR_PKG:
417
0
    tmp = g_getenv("CONFIGURATION_DIRECTORY");
418
0
    if (tmp != NULL && g_file_test(tmp, G_FILE_TEST_EXISTS))
419
0
      return g_build_filename(tmp, NULL);
420
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSCONFDIR);
421
0
    return g_build_filename(basedir, PACKAGE_NAME, NULL);
422
  /* /var/lib/fwupd */
423
0
  case FU_PATH_KIND_LOCALSTATEDIR_PKG:
424
0
    tmp = g_getenv("STATE_DIRECTORY");
425
0
    if (tmp != NULL && g_file_test(tmp, G_FILE_TEST_EXISTS))
426
0
      return g_build_filename(tmp, NULL);
427
0
    basedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR);
428
0
    return g_build_filename(basedir, "lib", PACKAGE_NAME, NULL);
429
  /* /var/lib/fwupd/quirks.d */
430
0
  case FU_PATH_KIND_LOCALSTATEDIR_QUIRKS:
431
0
    tmp = g_getenv("FWUPD_LOCALSTATEDIR_QUIRKS");
432
0
    if (tmp != NULL)
433
0
      return g_build_filename(tmp, NULL);
434
0
    basedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR_PKG);
435
0
    return g_build_filename(basedir, "quirks.d", NULL);
436
  /* /var/lib/fwupd/metadata */
437
0
  case FU_PATH_KIND_LOCALSTATEDIR_METADATA:
438
0
    tmp = g_getenv("FWUPD_LOCALSTATEDIR_METADATA");
439
0
    if (tmp != NULL)
440
0
      return g_build_filename(tmp, NULL);
441
0
    basedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR_PKG);
442
0
    return g_build_filename(basedir, "metadata", NULL);
443
  /* /var/lib/fwupd/remotes.d */
444
0
  case FU_PATH_KIND_LOCALSTATEDIR_REMOTES:
445
0
    tmp = g_getenv("FWUPD_LOCALSTATEDIR_REMOTES");
446
0
    if (tmp != NULL)
447
0
      return g_build_filename(tmp, NULL);
448
0
    basedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR_PKG);
449
0
    return g_build_filename(basedir, "remotes.d", NULL);
450
  /* /var/cache/fwupd */
451
0
  case FU_PATH_KIND_CACHEDIR_PKG:
452
0
    tmp = g_getenv("CACHE_DIRECTORY");
453
0
    if (tmp != NULL && g_file_test(tmp, G_FILE_TEST_EXISTS))
454
0
      return g_build_filename(tmp, NULL);
455
0
    basedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR);
456
0
    return g_build_filename(basedir, "cache", PACKAGE_NAME, NULL);
457
  /* /var/etc/fwupd */
458
0
  case FU_PATH_KIND_LOCALCONFDIR_PKG:
459
0
    tmp = g_getenv("LOCALCONF_DIRECTORY");
460
0
    if (tmp != NULL && g_file_test(tmp, G_FILE_TEST_EXISTS))
461
0
      return g_build_filename(tmp, NULL);
462
0
    basedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR);
463
0
    return g_build_filename(basedir, "etc", PACKAGE_NAME, NULL);
464
  /* /run/lock */
465
0
  case FU_PATH_KIND_LOCKDIR:
466
0
    tmp = g_getenv("FWUPD_LOCKDIR");
467
0
    if (tmp != NULL)
468
0
      return g_strdup(tmp);
469
0
    if (g_file_test("/run/lock", G_FILE_TEST_EXISTS))
470
0
      return g_strdup("/run/lock");
471
0
    return g_strdup("/var/run");
472
  /* /sys/class/firmware-attributes */
473
0
  case FU_PATH_KIND_SYSFSDIR_FW_ATTRIB:
474
0
    tmp = g_getenv("FWUPD_SYSFSFWATTRIBDIR");
475
0
    if (tmp != NULL)
476
0
      return g_strdup(tmp);
477
0
    basedir = fu_path_from_kind(FU_PATH_KIND_SYSFSDIR);
478
0
    return g_build_filename(basedir, "class", "firmware-attributes", NULL);
479
0
  case FU_PATH_KIND_POLKIT_ACTIONS:
480
#ifdef POLKIT_ACTIONDIR
481
    return g_strdup(POLKIT_ACTIONDIR);
482
#else
483
0
    return NULL;
484
0
#endif
485
  /* C:\Program Files (x86)\fwupd\ */
486
0
  case FU_PATH_KIND_WIN32_BASEDIR:
487
0
    return fu_path_get_win32_basedir();
488
  /* / */
489
0
  case FU_PATH_KIND_HOSTFS_ROOT:
490
0
    tmp = g_getenv("FWUPD_HOSTFS_ROOT");
491
0
    if (tmp != NULL)
492
0
      return g_strdup(tmp);
493
0
    return g_strdup("/");
494
  /* /boot */
495
0
  case FU_PATH_KIND_HOSTFS_BOOT:
496
0
    tmp = g_getenv("FWUPD_HOSTFS_BOOT");
497
0
    if (tmp != NULL)
498
0
      return g_strdup(tmp);
499
0
    return g_strdup("/boot");
500
  /* /dev */
501
0
  case FU_PATH_KIND_DEVFS:
502
0
    tmp = g_getenv("FWUPD_DEVFS");
503
0
    if (tmp != NULL)
504
0
      return g_strdup(tmp);
505
0
    return g_strdup("/dev");
506
  /* /etc/localtime or /var/lib/timezone/localtime */
507
0
  case FU_PATH_KIND_LOCALTIME: {
508
0
    g_autofree gchar *sysconfdir = fu_path_from_kind(FU_PATH_KIND_SYSCONFDIR);
509
0
    g_autofree gchar *localstatedir = fu_path_from_kind(FU_PATH_KIND_LOCALSTATEDIR);
510
0
    g_autofree gchar *localtime = NULL;
511
0
    tmp = g_getenv("FWUPD_LOCALTIME");
512
0
    if (tmp != NULL)
513
0
      return g_strdup(tmp);
514
0
    basedir = g_build_filename(localstatedir, "lib", "timezone", "localtime", NULL);
515
0
    if (g_file_test(basedir, G_FILE_TEST_EXISTS))
516
0
      return g_steal_pointer(&basedir);
517
0
    localtime = g_build_filename(sysconfdir, "localtime", NULL);
518
0
    if (g_file_test(localtime, G_FILE_TEST_EXISTS))
519
0
      return g_steal_pointer(&localtime);
520
0
    return g_strdup("/etc/localtime");
521
0
  }
522
  /* /sys/kernel/debug */
523
0
  case FU_PATH_KIND_DEBUGFSDIR:
524
0
    tmp = g_getenv("FWUPD_DEBUGFSDIR");
525
0
    if (tmp != NULL)
526
0
      return g_strdup(tmp);
527
0
    return g_strdup("/sys/kernel/debug");
528
  /* this shouldn't happen */
529
0
  default:
530
0
    g_warning("cannot build path for unknown kind %u", path_kind);
531
0
  }
532
533
0
  return NULL;
534
0
}
535
536
static gint
537
fu_path_glob_sort_cb(gconstpointer a, gconstpointer b)
538
0
{
539
0
  return g_strcmp0(*(const gchar **)a, *(const gchar **)b);
540
0
}
541
542
/**
543
 * fu_path_glob:
544
 * @directory: a directory path
545
 * @pattern: a glob pattern, e.g. `*foo*`
546
 * @error: (nullable): optional return location for an error
547
 *
548
 * Returns all the filenames that match a specific glob pattern.
549
 * Any results are sorted. No matching files will set @error.
550
 *
551
 * Returns:  (element-type utf8) (transfer container): matching files, or %NULL
552
 *
553
 * Since: 1.8.2
554
 **/
555
GPtrArray *
556
fu_path_glob(const gchar *directory, const gchar *pattern, GError **error)
557
0
{
558
0
  const gchar *basename;
559
0
  g_autoptr(GDir) dir = NULL;
560
0
  g_autoptr(GPtrArray) files = g_ptr_array_new_with_free_func(g_free);
561
562
0
  g_return_val_if_fail(directory != NULL, NULL);
563
0
  g_return_val_if_fail(pattern != NULL, NULL);
564
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
565
566
0
  dir = g_dir_open(directory, 0, error);
567
0
  if (dir == NULL)
568
0
    return NULL;
569
0
  while ((basename = g_dir_read_name(dir)) != NULL) {
570
0
    if (!g_pattern_match_simple(pattern, basename))
571
0
      continue;
572
0
    g_ptr_array_add(files, g_build_filename(directory, basename, NULL));
573
0
  }
574
0
  if (files->len == 0) {
575
0
    g_set_error_literal(error,
576
0
            FWUPD_ERROR,
577
0
            FWUPD_ERROR_NOT_FOUND,
578
0
            "no files matched pattern");
579
0
    return NULL;
580
0
  }
581
0
  g_ptr_array_sort(files, fu_path_glob_sort_cb);
582
0
  return g_steal_pointer(&files);
583
0
}
584
585
/**
586
 * fu_path_make_absolute:
587
 * @filename: a path to a filename, perhaps symlinked
588
 * @error: (nullable): optional return location for an error
589
 *
590
 * Returns the resolved absolute file name.
591
 *
592
 * Returns: (transfer full): path, or %NULL on error
593
 *
594
 * Since: 2.0.0
595
 **/
596
gchar *
597
fu_path_make_absolute(const gchar *filename, GError **error)
598
0
{
599
0
  char full_tmp[PATH_MAX];
600
601
0
  g_return_val_if_fail(filename != NULL, NULL);
602
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
603
604
0
#ifdef HAVE_REALPATH
605
0
  if (realpath(filename, full_tmp) == NULL) {
606
0
    g_set_error(error,
607
0
          FWUPD_ERROR,
608
0
          FWUPD_ERROR_INVALID_DATA,
609
0
          "cannot resolve path: %s",
610
0
          fwupd_strerror(errno));
611
0
    return NULL;
612
0
  }
613
#else
614
  if (_fullpath(full_tmp, filename, sizeof(full_tmp)) == NULL) {
615
    g_set_error(error,
616
          FWUPD_ERROR,
617
          FWUPD_ERROR_INVALID_DATA,
618
          "cannot resolve path: %s",
619
          fwupd_strerror(errno));
620
    return NULL;
621
  }
622
#endif
623
0
  if (!g_file_test(full_tmp, G_FILE_TEST_EXISTS)) {
624
0
    g_set_error(error,
625
0
          FWUPD_ERROR,
626
0
          FWUPD_ERROR_INVALID_DATA,
627
0
          "cannot find path: %s",
628
0
          full_tmp);
629
0
    return NULL;
630
0
  }
631
0
  return g_strdup(full_tmp);
632
0
}
633
634
/**
635
 * fu_path_get_symlink_target:
636
 * @filename: a path to a symlink
637
 * @error: (nullable): optional return location for an error
638
 *
639
 * Returns the symlink target.
640
 *
641
 * Returns: (transfer full): path, or %NULL on error
642
 *
643
 * Since: 2.0.0
644
 **/
645
gchar *
646
fu_path_get_symlink_target(const gchar *filename, GError **error)
647
0
{
648
0
  const gchar *target;
649
0
  g_autoptr(GFile) file = NULL;
650
0
  g_autoptr(GFileInfo) info = NULL;
651
652
0
  file = g_file_new_for_path(filename);
653
0
  info = g_file_query_info(file,
654
0
         G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
655
0
         G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
656
0
         NULL,
657
0
         error);
658
0
  if (info == NULL) {
659
0
    fwupd_error_convert(error);
660
0
    return NULL;
661
0
  }
662
0
  target =
663
0
      g_file_info_get_attribute_byte_string(info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
664
0
  if (target == NULL) {
665
0
    g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no symlink target");
666
0
    return NULL;
667
0
  }
668
669
  /* success */
670
0
  return g_strdup(target);
671
0
}