Coverage Report

Created: 2025-10-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-volume-locker.c
Line
Count
Source
1
/*
2
 * Copyright 2025 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuVolumeLocker"
8
9
#include "config.h"
10
11
#include "fu-volume-locker.h"
12
13
/**
14
 * FuVolumeLocker:
15
 *
16
 * Easily unmount a volume when an object goes out of scope.
17
 *
18
 * See also: [class@FuVolume]
19
 */
20
21
struct _FuVolumeLocker {
22
  GObject parent_instance;
23
  FuVolume *volume;
24
  gboolean is_open;
25
};
26
27
0
G_DEFINE_TYPE(FuVolumeLocker, fu_volume_locker, G_TYPE_OBJECT)
28
0
29
0
/**
30
0
 * fu_volume_locker_close:
31
0
 * @self: a #FuVolumeLocker
32
0
 * @error: (nullable): optional return location for an error
33
0
 *
34
0
 * Closes the volume before it gets cleaned up.
35
0
 *
36
0
 * This function can be used to manually unmount a volume managed by a locker,
37
0
 * and allows the caller to properly handle the error.
38
0
 *
39
0
 * Returns: %TRUE for success
40
0
 *
41
0
 * Since: 2.0.15
42
0
 **/
43
0
gboolean
44
0
fu_volume_locker_close(FuVolumeLocker *self, GError **error)
45
0
{
46
0
  g_autoptr(GError) error_local = NULL;
47
48
0
  g_return_val_if_fail(FU_IS_VOLUME_LOCKER(self), FALSE);
49
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
50
51
0
  if (!self->is_open)
52
0
    return TRUE;
53
0
  if (!fu_volume_unmount(self->volume, &error_local)) {
54
0
    if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND)) {
55
0
      g_debug("ignoring: %s", error_local->message);
56
0
      return TRUE;
57
0
    }
58
0
    g_propagate_error(error, g_steal_pointer(&error_local));
59
0
    return FALSE;
60
0
  }
61
62
  /* success */
63
0
  self->is_open = FALSE;
64
0
  return TRUE;
65
0
}
66
67
static void
68
fu_volume_locker_finalize(GObject *obj)
69
0
{
70
0
  FuVolumeLocker *self = FU_VOLUME_LOCKER(obj);
71
72
0
  if (self->is_open) {
73
0
    g_autoptr(GError) error_local = NULL;
74
0
    if (!fu_volume_unmount(self->volume, &error_local))
75
0
      g_warning("failed to close volume: %s", error_local->message);
76
0
  }
77
0
  if (self->volume != NULL)
78
0
    g_object_unref(self->volume);
79
0
  G_OBJECT_CLASS(fu_volume_locker_parent_class)->finalize(obj);
80
0
}
81
82
static void
83
fu_volume_locker_class_init(FuVolumeLockerClass *klass)
84
0
{
85
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
86
0
  object_class->finalize = fu_volume_locker_finalize;
87
0
}
88
89
static void
90
fu_volume_locker_init(FuVolumeLocker *self)
91
0
{
92
0
}
93
94
/**
95
 * fu_volume_locker_new:
96
 * @volume: a #GObject
97
 * @error: (nullable): optional return location for an error
98
 *
99
 * Locks the volume, mounting it and unmounting it as required. If the volume is
100
 * already mounted then it is is _not_ unmounted when the locker is closed.
101
 *
102
 * Returns: (transfer full): a volume locker if mounted, or %NULL
103
 *
104
 * Since: 2.0.15
105
 **/
106
FuVolumeLocker *
107
fu_volume_locker_new(FuVolume *volume, GError **error)
108
0
{
109
0
  g_autoptr(FuVolumeLocker) self = g_object_new(FU_TYPE_VOLUME_LOCKER, NULL);
110
111
0
  g_return_val_if_fail(FU_IS_VOLUME(volume), NULL);
112
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
113
114
  /* already open, so NOP */
115
0
  if (fu_volume_is_mounted(volume))
116
0
    return g_steal_pointer(&self);
117
118
  /* open volume */
119
0
  if (!fu_volume_mount(volume, error)) {
120
0
    g_autoptr(GError) error_local = NULL;
121
0
    if (!fu_volume_unmount(volume, &error_local)) {
122
0
      if (!g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO)) {
123
0
        g_debug("ignoring unmount error on aborted mount: %s",
124
0
          error_local->message);
125
0
      }
126
0
    }
127
0
    return NULL;
128
0
  }
129
130
  /* create object */
131
0
  self = g_object_new(FU_TYPE_VOLUME_LOCKER, NULL);
132
0
  self->is_open = TRUE;
133
0
  self->volume = g_object_ref(volume);
134
0
  return g_steal_pointer(&self);
135
0
}