Coverage Report

Created: 2025-07-01 07:09

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