Coverage Report

Created: 2026-01-09 07:21

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