Coverage Report

Created: 2025-06-13 06:55

/src/glib/gio/gpermission.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2010 Codethink Limited
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * Author: Ryan Lortie <desrt@desrt.ca>
20
 */
21
22
#include "config.h"
23
24
#include "gpermission.h"
25
26
#include "gioerror.h"
27
#include "gioenums.h"
28
#include "gasyncresult.h"
29
#include "gtask.h"
30
#include "glibintl.h"
31
32
33
/**
34
 * SECTION:gpermission
35
 * @title: GPermission
36
 * @short_description: An object representing the permission
37
 *     to perform a certain action
38
 * @include: gio/gio.h
39
 *
40
 * A #GPermission represents the status of the caller's permission to
41
 * perform a certain action.
42
 *
43
 * You can query if the action is currently allowed and if it is
44
 * possible to acquire the permission so that the action will be allowed
45
 * in the future.
46
 *
47
 * There is also an API to actually acquire the permission and one to
48
 * release it.
49
 *
50
 * As an example, a #GPermission might represent the ability for the
51
 * user to write to a #GSettings object.  This #GPermission object could
52
 * then be used to decide if it is appropriate to show a "Click here to
53
 * unlock" button in a dialog and to provide the mechanism to invoke
54
 * when that button is clicked.
55
 **/
56
57
/**
58
 * GPermission:
59
 *
60
 * #GPermission is an opaque data structure and can only be accessed
61
 * using the following functions.
62
 **/
63
64
struct _GPermissionPrivate
65
{
66
  gboolean allowed;
67
  gboolean can_acquire;
68
  gboolean can_release;
69
};
70
71
enum  {
72
  PROP_NONE,
73
  PROP_ALLOWED,
74
  PROP_CAN_ACQUIRE,
75
  PROP_CAN_RELEASE
76
};
77
78
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GPermission, g_permission, G_TYPE_OBJECT)
79
80
/**
81
 * g_permission_acquire:
82
 * @permission: a #GPermission instance
83
 * @cancellable: (nullable): a #GCancellable, or %NULL
84
 * @error: a pointer to a %NULL #GError, or %NULL
85
 *
86
 * Attempts to acquire the permission represented by @permission.
87
 *
88
 * The precise method by which this happens depends on the permission
89
 * and the underlying authentication mechanism.  A simple example is
90
 * that a dialog may appear asking the user to enter their password.
91
 *
92
 * You should check with g_permission_get_can_acquire() before calling
93
 * this function.
94
 *
95
 * If the permission is acquired then %TRUE is returned.  Otherwise,
96
 * %FALSE is returned and @error is set appropriately.
97
 *
98
 * This call is blocking, likely for a very long time (in the case that
99
 * user interaction is required).  See g_permission_acquire_async() for
100
 * the non-blocking version.
101
 *
102
 * Returns: %TRUE if the permission was successfully acquired
103
 *
104
 * Since: 2.26
105
 */
106
gboolean
107
g_permission_acquire (GPermission   *permission,
108
                      GCancellable  *cancellable,
109
                      GError       **error)
110
0
{
111
0
  g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
112
0
  return G_PERMISSION_GET_CLASS (permission)
113
0
    ->acquire (permission, cancellable, error);
114
0
}
115
116
/**
117
 * g_permission_acquire_async:
118
 * @permission: a #GPermission instance
119
 * @cancellable: (nullable): a #GCancellable, or %NULL
120
 * @callback: the #GAsyncReadyCallback to call when done
121
 * @user_data: the user data to pass to @callback
122
 *
123
 * Attempts to acquire the permission represented by @permission.
124
 *
125
 * This is the first half of the asynchronous version of
126
 * g_permission_acquire().
127
 *
128
 * Since: 2.26
129
 **/
130
void
131
g_permission_acquire_async (GPermission         *permission,
132
                            GCancellable        *cancellable,
133
                            GAsyncReadyCallback  callback,
134
                            gpointer             user_data)
135
0
{
136
0
  g_return_if_fail (G_IS_PERMISSION (permission));
137
0
  G_PERMISSION_GET_CLASS (permission)
138
0
    ->acquire_async (permission, cancellable, callback, user_data);
139
0
}
140
141
/**
142
 * g_permission_acquire_finish:
143
 * @permission: a #GPermission instance
144
 * @result: the #GAsyncResult given to the #GAsyncReadyCallback
145
 * @error: a pointer to a %NULL #GError, or %NULL
146
 *
147
 * Collects the result of attempting to acquire the permission
148
 * represented by @permission.
149
 *
150
 * This is the second half of the asynchronous version of
151
 * g_permission_acquire().
152
 *
153
 * Returns: %TRUE if the permission was successfully acquired
154
 *
155
 * Since: 2.26
156
 **/
157
gboolean
158
g_permission_acquire_finish (GPermission   *permission,
159
                             GAsyncResult  *result,
160
                             GError       **error)
161
0
{
162
0
  g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
163
0
  return G_PERMISSION_GET_CLASS (permission)
164
0
    ->acquire_finish (permission, result, error);
165
0
}
166
167
/**
168
 * g_permission_release:
169
 * @permission: a #GPermission instance
170
 * @cancellable: (nullable): a #GCancellable, or %NULL
171
 * @error: a pointer to a %NULL #GError, or %NULL
172
 *
173
 * Attempts to release the permission represented by @permission.
174
 *
175
 * The precise method by which this happens depends on the permission
176
 * and the underlying authentication mechanism.  In most cases the
177
 * permission will be dropped immediately without further action.
178
 *
179
 * You should check with g_permission_get_can_release() before calling
180
 * this function.
181
 *
182
 * If the permission is released then %TRUE is returned.  Otherwise,
183
 * %FALSE is returned and @error is set appropriately.
184
 *
185
 * This call is blocking, likely for a very long time (in the case that
186
 * user interaction is required).  See g_permission_release_async() for
187
 * the non-blocking version.
188
 *
189
 * Returns: %TRUE if the permission was successfully released
190
 *
191
 * Since: 2.26
192
 **/
193
gboolean
194
g_permission_release (GPermission   *permission,
195
                      GCancellable  *cancellable,
196
                      GError       **error)
197
0
{
198
0
  g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
199
0
  return G_PERMISSION_GET_CLASS (permission)
200
0
    ->release (permission, cancellable, error);
201
0
}
202
203
/**
204
 * g_permission_release_async:
205
 * @permission: a #GPermission instance
206
 * @cancellable: (nullable): a #GCancellable, or %NULL
207
 * @callback: the #GAsyncReadyCallback to call when done
208
 * @user_data: the user data to pass to @callback
209
 *
210
 * Attempts to release the permission represented by @permission.
211
 *
212
 * This is the first half of the asynchronous version of
213
 * g_permission_release().
214
 *
215
 * Since: 2.26
216
 **/
217
void
218
g_permission_release_async (GPermission         *permission,
219
                            GCancellable        *cancellable,
220
                            GAsyncReadyCallback  callback,
221
                            gpointer             user_data)
222
0
{
223
0
  g_return_if_fail (G_IS_PERMISSION (permission));
224
0
  G_PERMISSION_GET_CLASS (permission)
225
0
    ->release_async (permission, cancellable, callback, user_data);
226
0
}
227
228
/**
229
 * g_permission_release_finish:
230
 * @permission: a #GPermission instance
231
 * @result: the #GAsyncResult given to the #GAsyncReadyCallback
232
 * @error: a pointer to a %NULL #GError, or %NULL
233
 *
234
 * Collects the result of attempting to release the permission
235
 * represented by @permission.
236
 *
237
 * This is the second half of the asynchronous version of
238
 * g_permission_release().
239
 *
240
 * Returns: %TRUE if the permission was successfully released
241
 *
242
 * Since: 2.26
243
 **/
244
gboolean
245
g_permission_release_finish (GPermission   *permission,
246
                             GAsyncResult  *result,
247
                             GError       **error)
248
0
{
249
0
  g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
250
0
  return G_PERMISSION_GET_CLASS (permission)
251
0
    ->release_finish (permission, result, error);
252
0
}
253
254
/**
255
 * g_permission_get_allowed:
256
 * @permission: a #GPermission instance
257
 *
258
 * Gets the value of the 'allowed' property.  This property is %TRUE if
259
 * the caller currently has permission to perform the action that
260
 * @permission represents the permission to perform.
261
 *
262
 * Returns: the value of the 'allowed' property
263
 *
264
 * Since: 2.26
265
 **/
266
gboolean
267
g_permission_get_allowed (GPermission *permission)
268
0
{
269
0
  g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
270
0
  return permission->priv->allowed;
271
0
}
272
273
/**
274
 * g_permission_get_can_acquire:
275
 * @permission: a #GPermission instance
276
 *
277
 * Gets the value of the 'can-acquire' property.  This property is %TRUE
278
 * if it is generally possible to acquire the permission by calling
279
 * g_permission_acquire().
280
 *
281
 * Returns: the value of the 'can-acquire' property
282
 *
283
 * Since: 2.26
284
 **/
285
gboolean
286
g_permission_get_can_acquire (GPermission *permission)
287
0
{
288
0
  g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
289
0
  return permission->priv->can_acquire;
290
0
}
291
292
/**
293
 * g_permission_get_can_release:
294
 * @permission: a #GPermission instance
295
 *
296
 * Gets the value of the 'can-release' property.  This property is %TRUE
297
 * if it is generally possible to release the permission by calling
298
 * g_permission_release().
299
 *
300
 * Returns: the value of the 'can-release' property
301
 *
302
 * Since: 2.26
303
 **/
304
gboolean
305
g_permission_get_can_release (GPermission *permission)
306
0
{
307
0
  g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
308
0
  return permission->priv->can_release;
309
0
}
310
311
/**
312
 * g_permission_impl_update:
313
 * @permission: a #GPermission instance
314
 * @allowed: the new value for the 'allowed' property
315
 * @can_acquire: the new value for the 'can-acquire' property
316
 * @can_release: the new value for the 'can-release' property
317
 *
318
 * This function is called by the #GPermission implementation to update
319
 * the properties of the permission.  You should never call this
320
 * function except from a #GPermission implementation.
321
 *
322
 * GObject notify signals are generated, as appropriate.
323
 *
324
 * Since: 2.26
325
 **/
326
void
327
g_permission_impl_update (GPermission *permission,
328
                          gboolean     allowed,
329
                          gboolean     can_acquire,
330
                          gboolean     can_release)
331
0
{
332
0
  GObject *object;
333
334
0
  g_return_if_fail (G_IS_PERMISSION (permission));
335
336
0
  object = G_OBJECT (permission);
337
0
  g_object_freeze_notify (object);
338
339
0
  allowed = allowed != FALSE;
340
0
  if (allowed != permission->priv->allowed)
341
0
    {
342
0
      permission->priv->allowed = allowed;
343
0
      g_object_notify (object, "allowed");
344
0
    }
345
346
0
  can_acquire = can_acquire != FALSE;
347
0
  if (can_acquire != permission->priv->can_acquire)
348
0
    {
349
0
      permission->priv->can_acquire = can_acquire;
350
0
      g_object_notify (object, "can-acquire");
351
0
    }
352
353
0
  can_release = can_release != FALSE;
354
0
  if (can_release != permission->priv->can_release)
355
0
    {
356
0
      permission->priv->can_release = can_release;
357
0
      g_object_notify (object, "can-release");
358
0
    }
359
360
0
  g_object_thaw_notify (object);
361
0
}
362
363
static void
364
g_permission_get_property (GObject *object, guint prop_id,
365
                           GValue *value, GParamSpec *pspec)
366
0
{
367
0
  GPermission *permission = G_PERMISSION (object);
368
369
0
  switch (prop_id)
370
0
    {
371
0
    case PROP_ALLOWED:
372
0
      g_value_set_boolean (value, permission->priv->allowed);
373
0
      break;
374
375
0
    case PROP_CAN_ACQUIRE:
376
0
      g_value_set_boolean (value, permission->priv->can_acquire);
377
0
      break;
378
379
0
    case PROP_CAN_RELEASE:
380
0
      g_value_set_boolean (value, permission->priv->can_release);
381
0
      break;
382
383
0
    default:
384
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
385
0
  }
386
0
}
387
388
static void
389
g_permission_init (GPermission *permission)
390
0
{
391
0
  permission->priv = g_permission_get_instance_private (permission);
392
0
}
393
394
static gboolean
395
acquire_or_release (GPermission   *permission,
396
                    GCancellable  *cancellable,
397
                    GError       **error)
398
0
{
399
0
  g_set_error_literal  (error,
400
0
                        G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
401
0
                        "Can't acquire or release permission");
402
0
  return FALSE;
403
0
}
404
405
static void
406
acquire_or_release_async (GPermission         *permission,
407
                          GCancellable        *cancellable,
408
                          GAsyncReadyCallback  callback,
409
                          gpointer             user_data)
410
0
{
411
0
  g_task_report_new_error (permission,
412
0
                           callback, user_data,
413
0
                           NULL,
414
0
                           G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
415
0
                           "Can't acquire or release permission");
416
0
}
417
418
static gboolean
419
acquire_or_release_finish (GPermission   *permission,
420
                           GAsyncResult  *result,
421
                           GError       **error)
422
0
{
423
0
  return g_task_propagate_boolean (G_TASK (result), error);
424
0
}
425
426
static void
427
g_permission_class_init (GPermissionClass *class)
428
0
{
429
0
  GObjectClass *object_class = G_OBJECT_CLASS (class);
430
431
0
  object_class->get_property = g_permission_get_property;
432
433
0
  class->acquire = acquire_or_release;
434
0
  class->release = acquire_or_release;
435
0
  class->acquire_async = acquire_or_release_async;
436
0
  class->release_async = acquire_or_release_async;
437
0
  class->acquire_finish = acquire_or_release_finish;
438
0
  class->release_finish = acquire_or_release_finish;
439
440
  /**
441
   * GPermission:allowed:
442
   *
443
   * %TRUE if the caller currently has permission to perform the action that
444
   * @permission represents the permission to perform.
445
   */
446
0
   g_object_class_install_property (object_class, PROP_ALLOWED,
447
0
     g_param_spec_boolean ("allowed",
448
0
                           P_("Is allowed"),
449
0
                           P_("If the caller is allowed to perform the action"),
450
0
                           FALSE,
451
0
                           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
452
453
  /**
454
   * GPermission:can-acquire:
455
   *
456
   * %TRUE if it is generally possible to acquire the permission by calling
457
   * g_permission_acquire().
458
   */
459
0
   g_object_class_install_property (object_class, PROP_CAN_ACQUIRE,
460
0
     g_param_spec_boolean ("can-acquire",
461
0
                           P_("Can acquire"),
462
0
                           P_("If calling g_permission_acquire() makes sense"),
463
0
                           FALSE,
464
0
                           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
465
466
  /**
467
   * GPermission:can-release:
468
   *
469
   * %TRUE if it is generally possible to release the permission by calling
470
   * g_permission_release().
471
   */
472
0
   g_object_class_install_property (object_class, PROP_CAN_RELEASE,
473
0
     g_param_spec_boolean ("can-release",
474
0
                           P_("Can release"),
475
0
                           P_("If calling g_permission_release() makes sense"),
476
0
                           FALSE,
477
0
                           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
478
0
}