Coverage Report

Created: 2025-06-13 06:55

/src/glib/gio/gtrashportal.c
Line
Count
Source (jump to first uncovered line)
1
/* GIO - GLib Input, Output and Streaming Library
2
 *
3
 * Copyright 2018, Red Hat, Inc.
4
 *
5
 * SPDX-License-Identifier: LGPL-2.1-or-later
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General
18
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "config.h"
22
23
#include <sys/stat.h>
24
#include <fcntl.h>
25
#include <errno.h>
26
#include <string.h>
27
28
#include "gtrashportal.h"
29
#include "xdp-dbus.h"
30
#include "gstdio.h"
31
32
#ifdef G_OS_UNIX
33
#include "gunixfdlist.h"
34
#endif
35
36
#ifndef O_CLOEXEC
37
#define O_CLOEXEC 0
38
#else
39
#define HAVE_O_CLOEXEC 1
40
#endif
41
42
#ifndef O_PATH
43
#define O_PATH 0
44
#endif
45
46
static GXdpTrash *
47
ensure_trash_portal (void)
48
0
{
49
0
  static GXdpTrash *trash = NULL;
50
51
0
  if (g_once_init_enter (&trash))
52
0
    {
53
0
      GDBusConnection *connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
54
0
      GXdpTrash *proxy = NULL;
55
56
0
      if (connection != NULL)
57
0
        {
58
0
          proxy = gxdp_trash_proxy_new_sync (connection, 0,
59
0
                                             "org.freedesktop.portal.Desktop",
60
0
                                             "/org/freedesktop/portal/desktop",
61
0
                                             NULL, NULL);
62
0
          g_object_unref (connection);
63
0
        }
64
65
0
      g_once_init_leave (&trash, proxy);
66
0
    }
67
68
0
  return trash;
69
0
}
70
71
gboolean
72
g_trash_portal_trash_file (GFile   *file,
73
                           GError **error)
74
0
{
75
0
  char *path = NULL;
76
0
  GUnixFDList *fd_list = NULL;
77
0
  int fd, fd_in, errsv;
78
0
  gboolean ret = FALSE;
79
0
  guint portal_result = 0;
80
0
  GXdpTrash *proxy;
81
82
0
  proxy = ensure_trash_portal ();
83
0
  if (proxy == NULL)
84
0
    {
85
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED,
86
0
                   "Trash portal is not available");
87
0
      goto out;
88
0
    }
89
90
0
  path = g_file_get_path (file);
91
92
0
  fd = g_open (path, O_RDWR | O_CLOEXEC | O_NOFOLLOW);
93
0
  if (fd == -1 && errno == EISDIR)
94
    /* If it is a directory, fall back to O_PATH.
95
     * Remove O_NOFOLLOW since
96
     * a) we know it is a directory, not a symlink, and
97
     * b) the portal reject this combination
98
     */
99
0
    fd = g_open (path, O_PATH | O_CLOEXEC | O_RDONLY);
100
101
0
  errsv = errno;
102
103
0
  if (fd == -1)
104
0
    {
105
0
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
106
0
                   "Failed to open %s", path);
107
0
      goto out;
108
0
    }
109
110
#ifndef HAVE_O_CLOEXEC
111
  fcntl (fd, F_SETFD, FD_CLOEXEC);
112
#endif
113
114
0
  fd_list = g_unix_fd_list_new ();
115
0
  fd_in = g_unix_fd_list_append (fd_list, fd, error);
116
0
  g_close (fd, NULL);
117
118
0
  if (fd_in == -1)
119
0
    goto out;
120
121
0
  ret = gxdp_trash_call_trash_file_sync (proxy,
122
0
                                         g_variant_new_handle (fd_in),
123
0
                                         fd_list,
124
0
                                         &portal_result,
125
0
                                         NULL,
126
0
                                         NULL,
127
0
                                         error);
128
129
0
  if (ret && portal_result != 1)
130
0
    {
131
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Trash portal failed on %s", path);
132
0
      ret = FALSE;
133
0
    }
134
135
0
 out:
136
0
  g_clear_object (&fd_list);
137
0
  g_free (path);
138
139
0
  return ret;
140
0
}